声明:文中知识体系目录来自 dva.js 知识导图

本文阅读时间大概为 5 分钟,但是能让你了解基于 umi 和 dva 构建项目的最小知识体系,你可以粗略的浏览一下本文所提到的知识,在后续的讲解中都会多次重复提起,保证学习效率。

由于现在前端工程化的流行,所以在学习一个新的框架时,可能会面临一些疑惑。

拿 react 举例:

  • es6 特性好多啊(es5 我都还没学完呢)
  • component 有三种写法(茴字的四种写法了解一下)
  • webpack 是什么(前端构建工具,然后呢,webpack是什么?)
  • 什么同步异步数据流(我 callback 都理不清楚)

ECMAScript 6

变量声明

const 用于声明常量,let 用于声明变量,他们都是块级作用域。

  1. const a = 1;
  2. let b = 1;

模板字符串

用于拼接字符串。

  1. let a = 'hello';
  2. let b = 'hello';
  3. console.log('print:' + a + b);
  4. let c = `print:${a}${b}`
  5. // 注意这个不是引号,键盘 esc 下面那个按键

默认参数

  1. function test(a = 'world') {
  2. console.log(`print:hello,${a}`);
  3. }
  4. test();
  5. // print:hello,world

箭头函数

函数的简化写法。

  1. function test(a = 'world') {
  2. console.log(`print:hello,${a}`);
  3. }
  4. const test = (a = 'world') => {
  5. console.log(`print:hello,${a}`);
  6. };

模块的导入和导出

  1. // 从 antd 中导入按钮组件
  2. import { Button } from 'antd';
  3. // 导出一个方法,这样就能在其他文件使用 `import` 导入使用了
  4. const test = (a = 'world') => {
  5. console.log(`print:hello,${a}`);
  6. };
  7. export default test;

析构赋值

  1. const obj = { key: 'umi', author: 'sorrycc' };
  2. console.log(obj.key);
  3. const { key } = obj;
  4. // 等价于 `const key = obj.key;`
  5. const obj2 = { key };
  6. // 等价于 `const obj2 = { key: key };`;
  7. // 数组也有类似的用法
  8. const arr = [1, 2];
  9. const [foo, bar] = arr;
  10. console.log(foo);
  11. // 1

展开运算符

用于数组组装:

  1. const arr = ['umi'];
  2. const texts = [...arr, 'dva'];
  3. // texts => ['umi', 'dva']

用于取出数组部分属性:

  1. const arr = ['umi', 'dva', 'antd'];
  2. const [umi, ...other] = arr;
  3. // 前面已经提过析构赋值,所以第一项会赋值给 `umi`,剩下的会被组合成一个 `other` 数组
  4. console.log(umi);
  5. // umi
  6. console.log(other);
  7. // (2)['dva', 'antd']

用于组合新的对象,key 相同时,靠后展开的值会覆盖靠前的值:

  1. const obj = { a: 1, b: 2 };
  2. const obj2 = { b: 3, c: 4 };
  3. const obj3 = { ...obj, ...obj2 };
  4. // obj3 => { a: 1, b: 3, c: 4 }

JSX

组件嵌套

类似 html 。

  1. <app>
  2. <Header />
  3. <Footer />
  4. </app>

className

class 是 Javascript 的保留词,所以添加样式类名时,需用 className 代替 class

  1. <h1 className="fancy">Hello Umi</h1>

JavaScript 表达式

JavaScript 表达式需要用 {} 括起来,会执行并返回结果。

  1. <h1>{this.props.title}</h1>

注释

尽量不要使用 // 做单行注释。

  1. <h1>
  2. {/* multiline comment */}
  3. {/*
  4. multi
  5. line
  6. comment
  7. */}
  8. {
  9. // single line
  10. }
  11. Hello
  12. </h1>

理解 CSS Modules

示例

  1. import styles from './example.css';
  2. const Example = (<button className={styles.button}>Click me</button>);
  3. /**
  4. * .button {
  5. * background-color: #1890ff;
  6. * }
  7. */

你不必理解 CSS Modules 的工作原理,只需要知道 import from 使得被引用的样式文件可以只作用在引用它的地方,而不会全局生效。例如上述示例的 styles.button 在构建之后可能会被重命名为 ProductList_button_1FU0u ,而不再是 buttonProductList_button_1FU0u 是全局生效的,而 styles.button 只在当前文件有效。这样,你可以为样式类名起一个简短的描述性名字,而不需要关心命名冲突问题。


Dva

Model

在 umi 项目中,你可以使用 dva 来处理数据流,以响应一些复杂的交互操作。这些处理数据流的文件统一放在 models 文件夹下,每一个文件默认导出一个对象,里面包含数据和处理数据的方法,通常我们称之为 model 。一个 model 文件的结构一般是这样的:

  1. export default {
  2. namespace: 'example', // 这个 model 的名字,必须全局唯一
  3. state: {
  4. count: 0,
  5. }, // 初始数据
  6. reducers: {
  7. save() { ... },
  8. }, // 用于修改数据
  9. effects: {
  10. *getData() { ... },
  11. }, // 用于获取数据
  12. subscriptions: {
  13. setup() { ... },
  14. }, // 用于订阅数据
  15. }

Reducer

每一个 reducer 都是一个普通函数,接受 state 和 action 作为参数,即:(state, action) => state ,你可以在函数中更改旧的 state,返回新的 state 。

  1. reducers: {
  2. save(state, { payload }) {
  3. return ({ ...state, ...payload });
  4. },
  5. },

Effect

每一个 effect 都是一个 生成器函数 ,你可以在这里获取你需要的数据,例如向服务器发起一个请求、或是获取其他 model 里的 state 。为了明确分工,你无法在 effect 中直接修改 state ,但你可以通过 put 方法 调用 reducer 来修改 state 。

  1. state:{
  2. assets:{},
  3. },
  4. *changeAssets({ payload }, { call, put, select }) {
  5. const user = yield select(states => states.user);
  6. const assets = yield call(fetchData, user);
  7. yield put({ type: 'save', payload: { assets } });
  8. },

select

此方法用于获取当前或其他 model 的 state 。

  1. const data = yield select(states => states[namespace]);

call

此方法用于执行一个异步函数,可以理解为等待这个函数执行结束。项目中常用于发送 http 请求,等待服务端响应数据。

  1. const data = yield call(doSomethingFunc, parameter);

put

此方法用于触发一个 action,这个 action 既可以是一个 reducer 也可以是一个 effect 。

  1. yield put({ type: 'reducerName', payload: { page } });

Subscription

subscription 用于订阅一个数据源,根据需要使用 dispatch 触发相应的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。 项目中常用于页面初始化数据的自动请求,如:

  1. subscriptions: {
  2. setup({ dispatch, history }) {
  3. return history.listen(({ pathname, query }) => {
  4. // 进入 '/home' 路由,发起一个名叫 'query' 的 effect
  5. if (pathname === '/home') {
  6. dispatch({ type: 'query' });
  7. }
  8. });
  9. },
  10. },

(model,page和其他)

dispatch

类似 effect 中的 put 方法,你可以在 subscription 的参数、或是一个已经 connect 过的组件的 props 中拿到。

connect

通过此方法在你的组件中获取到指定 model 的 state 数据。
示例

  1. import { connect } from 'dva';
  2. function App({ user, dispatch }) {
  3. const handleClick = () => {
  4. dispatch({ type: 'user/fetchUser' });
  5. };
  6. return (
  7. <div>
  8. <h2>Hello, {user}</h2>
  9. <button onClick={handleClick}>Click me</button>
  10. </div>
  11. );
  12. }
  13. export default connect(({ user }) => ({ user }))(App);

以上内容,几乎包括了所有我们在实际项目中会使用到的所有知识。 需要强调的是,文中内容仅仅是我为了让大家便于理解,做了一些简化描述。 相关概念,大家可以在对 umi 稍微熟悉之后,参阅官方文档

声明:文中知识体系目录来自开源项目:dva.js知识导图

—————————————————————————————————————————————————
原文链接:https://www.yuque.com/umijs/umi