赖同学


  • 首页

  • 标签

  • 分类

  • 归档

  • 站点地图

  • 留言

  • 搜索

Dva 学习笔记 (上)

发表于 July 6, 2018|分类于 react相关|阅读次数: –
字数统计: 2005|阅读时间: 11 min

dva 学习笔记

dva 学习笔记 代码

安装 dva-cli


npm install dva-cli -g

创建新应用

dva new dva-quickstart

这会创建 dva-quickstart 目录,包含项目初始化目录和文件,并提供开发服务器,构建脚本,数据 mock 服务,代理服务器等功能

然后我们 cd 进入 dva-quickstart 目录,并启动开发服务器:

cd dva-quickstart

npm start

使用 antd


通过 npm 安装 antd 和 babel-plugin-import 。 babel-plugin-import 是用来按需加载 antd 的脚本和样式的

npm install antd babel-plugin-import --save

编辑 .webpackrc ,使 babel-plugin-import 插件生效。

{
+  "extraBabelPlugins": [
+    ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
+  ]
}

定义路由

们要写个应用来先显示产品列表。首先第一步是创建路由,路由可以想象成是组成应用的不同页面。

新建 route component routes / Products.js 添加路由信息到路由表,编辑 router.js

Products.js

import React from 'react';
const Products = (props) => <h2>List of Products</h2>

export default Products;

`router.js`
import React from 'react';
import { Router, Route, Switch } from 'dva/router';
import IndexPage from './routes/IndexPage';
import Products from './routes/Products';
function RouterConfig({ history }) {
  return (
    <Router history={history}>
      <Switch>
        <Route path="/" exact component={IndexPage} />
        <Route path="/products" exact component={Products} />
      </Switch>
    </Router>
  );
}

export default RouterConfig;

编写 UI Component


随着应用的发展,你会需要在多个页面分享 UI 元素 (或在一个页面使用多次),在 dva 里你可以把这部分抽成 component 。

我们来编写一个 ProductList component ,这样就能在不同的地方显示产品列表了。

新建 components/ProductList.js 文件:

import React from 'react';
import PropTypes from 'prop-types';
import { Table, Popconfirm, Button } from 'antd';

const ProductList = ({ onDelete, products }) => {
  const columns = [{
    title: 'Name',
    dataIndex: 'name',
  }, {
    title: 'Actions',
    render: (text, record) => {
      return (
        <Popconfirm title="Delete?" onConfirm={() => onDelete(record.id)}>
          <Button>Delete</Button>
        </Popconfirm>
      );
    },
  }];
  return (
    <Table
      dataSource={products}
      columns={columns}
    />
  );
};

ProductList.propTypes = {
  onDelete: PropTypes.func.isRequired,
  products: PropTypes.array.isRequired,
};

export default ProductList;

定义 Model


完成 UI 后,现在开始处理数据和逻辑。

dva 通过 model 的概念把一个领域的模型管理起来,包含同步更新 state 的 reducers ,处理异步逻辑的 effects ,订阅数据源的 subscriptions 。

新建 model models / products.js :

export default {
  namespace: 'products',
  state: [],
  reducers: {
    'delete'(state, { payload: id }) {
      return state.filter(item => item.id !== id);
    },
  },
};

这个 model 里:

namespace 表示在全局 state 上的 key

state 是初始值,在这里是空数组 reducers 等同于 redux 里的 reducer 接收 action ,同步更新 state

然后别忘记在 index.js 里载入他:

connect 起来

这里,我们已经单独完成了 model 和 component ,那么他们如何串联起来呢?

dva 提供了 connect 方法。如果你熟悉 redux ,这个 connect 就是 react-redux 的 connect 。

编辑 routes / Products.js ,替换为以下内容:

import React from 'react';
import { connect } from 'dva';
import ProductList from '../components/ProductList';

const Products = ({ dispatch, products }) => {
  function handleDelete(id) {
    dispatch({
      type: 'products/delete',
      payload: id,
    });
  }
  return (
    <div>
      <h2>List of Products</h2>
      <ProductList onDelete={handleDelete} products={products} />
    </div>
  );
};

// export default Products;
export default connect(({ products }) => ({
  products,
}))(Products);

最后,我们还需要一些初始数据让这个应用 run 起来。编辑 index.js :

- 'const app = dva();'
+ const app = dva({
+   initialState: {
+     products: [
+       { name: 'dva', id: 1 },
+       { name: 'antd', id: 2 },
+     ],
+   },
+ });

Dva 概念

数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由跳转等)触发的,当此类行为会改变数据的时候可以通过 dispath 发起一个 action ,如果是同步行为就会直接通过 Reducers 改变 state , 如果是异步行为(副作用)会先触发 Effects 然后流向 Reducers 最终改变 State ,所以在 dva 中,数据流向非常清晰简明,并且思路基本跟开源社区保持一致

Models


State

type State = any

State 表示 Model 的状态数据,通常表现为一个 javascript 对象(可以为任何值),操作的时候每次都要当作不可变数据来对待,保证每次都是全新对象,没有引用关系,这样才能保证 State 的独立性,便于测试和追踪变化

在 dva 中可以通过 dva 的实例属性 _store 看到顶部的 state 数据,但是通常会很少用到

const app = dva();

console.log(app._store); // 顶部的 state 数据

Action

type AsyncAction = any

Action 是一个普通 javascript 对象,它是改变 State 的唯一途径。无论是从 UI 事件、网络回调还是 WebSocket 等数据源获得的数据,最终都会通过 dispatch 函数调用一个 action , 从而改变对应的数据。 action 必须带有 type 属性指明具体的行为,其他字段可以自定义,如果要发起一个 action 需要使用 dispatch 函数,需要注意的是 dispatch 是在组件 connect Models 后,通过 props 传入的

dispatch({ type : 'add' })

dispatch 函数

type dispatch = (a : Action) => Action

dispatching function 是一个用于触发 action 的函数, action 是改变 State 的唯一途径,但是它只描述了一个行为,而 dispatch 可以看做是触发这个行为的方式,而 Reducer 则是描述如何改变数据的

在 dva 中。 connect Models 的组件通过 props 可以访问到 dispatch ,可以调用 Model 中的 Reducer 或者 Effect ,常见的形式如下

dispatch({ type : 'user/add', payload : {} //需要传递的信息 }) //如果在 model 外调用,需要添加 namespace

Reducer

type Reducer<S, A> = (state: S, action: A) => S

Reducer 也称为 reducing function 函数接受两个参数:之前已经积累运算的结果和当前要被积累的值,返回的是一个新的积累的结果。该函数把一个集合归并成一个单值。

Reducer 的概念来自是函数式编程,很多语言中都有 reduce API

[{x:1},{y:2},{z:3}].reduce(function(prev, next){
  return Object.assign(prev, next);
})

//return {x:1, y:2, z:3}

在 dva 中, reducers 聚合积累的结果时间当前 model 的 state 对象。通过 actions 中传入的值,与当前 reducers 中的值进行运算获得新的值(也就是新的 state )。需要注意的是 Reducer 必须是纯函数,所以同样输入必然得到同样的输出,它们不应该产生任何副作用。并且, 每一次计算都应该使用 immutable date , 这种特征简单理解就是每次操作都是返回一个全新的数据(独立、纯净),所以热重载和时间旅行这些功能才能够使用

Effect

Effect 被称为副作用,在我们的应用中,最常见的就是异步操作,它来自于函数编程的概念,之所以叫副作用的原因是它使得我们的函数变得不纯,同样的输入不一定是同样的输出

dva 为了控制副作用的操作,底层引入了 redux-sagas 做异步流程控制,由于采用了 generator 的相关概念,所以将异步转成同步写法,从而将 effect 转为了纯函数。

Subscirption

Subscription 是一种从源获取数据的方法,它来自于 elm

Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action 。数据源可以当前的世界,服务器的 websocket 连接, keyboard 输入, geolocation 变化, history 路由变化等等

import key from 'keymaster';
app.model({
  namespace:'count',
  subscriptions:{
    keyEvent({dispatch}){
      key('⌘+up, ctrl+up', () => { dispatch({type:'add'}) })
    }
  }
})

Router

这里的路由是指前端路由,由于我们的应用通常是单页应用,所以需要前端代码来控制路由逻辑,通过浏览器提供的 History Api 可以监听到浏览器 url 的变化,从而控制路由相关操作

dva 实例提供了 router 方法来控制路由,使用的是 react-router

import { Router, Route } from 'dva/router';
app.router( ({history}) =>
 <Router history = {history}>
    <Route path="/" componet = {HomePage}>
 </Router>
 );

Router Components

Container Components 在 dva 中我们通常将其约束为 Route Component , 因为在 dva 中是以也页面维度来设计 Components

dva 中,通常需要 connect Model 的组件都是 Route Components , 组织在 /routers/ 目录下,而 /compoents/ 目录下的则是纯组件

dva
Dva 学习笔记 (中)
React 高级指引 D1
  • 文章目录
  • 站点概览
  1. 1.<code>dva</code> 学习笔记
    1. 1.创建新应用
    2. 2.定义路由
    3. 3.<code>connect</code> 起来
    4. 4.<code>Dva</code> 概念
      1. 1.<code>State</code>
      2. 2.<code>Action</code>
      3. 3.<code>dispatch</code> 函数
      4. 4.<code>Reducer</code>
      5. 5.<code>Effect</code>
      6. 6.<code>Subscirption</code>
    5. 5.Router
      1. 1.<code>Router Components</code>
© 2018 — 2023赖彬鸿
1.6k
载入天数...载入时分秒...
0%