Dva.js总结

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dva.js总结相关的知识,希望对你有一定的参考价值。

参考技术A [图片上传失败...(image-57ff75-1611135362899)]

课堂实战

1.index.js

2.router.js

3.connect连接model

4.跳转路由

发dispatch的时候带一个callback

当判断code成功的时候 执行回调

dispatch函数执行后返回是一个Promise
effects里面调用的函数可以返回值
返回值相当于这个Promise里resolve(这个值)。可以被.then的第一个回调参数拿到

003-and design-dva.js 知识导图-01-Reducer,Effect,Subscription,Router,dva配置,工具

一、Reducer

reducer 是一个函数,接受 state 和 action,返回老的或新的 state 。即:(state, action) => state

增删改

以 todos 为例。

app.model({
  namespace: ‘todos‘,
  state: [],
  reducers: {
    add(state, { payload: todo }) {
      return state.concat(todo);
    },
    remove(state, { payload: id }) {
      return state.filter(todo => todo.id !== id);
    },
    update(state, { payload: updatedTodo }) {
      return state.map(todo => {
        if (todo.id === updatedTodo.id) {
          return { ...todo, ...updatedTodo };
        } else {
          return todo;
        }
      });
    },
  },
};

嵌套数据的增删改

建议最多一层嵌套,以保持 state 的扁平化,深层嵌套会让 reducer 很难写和难以维护。

app.model({
  namespace: ‘app‘,
  state: {
    todos: [],
    loading: false,
  },
  reducers: {
    add(state, { payload: todo }) {
      const todos = state.todos.concat(todo);
      return { ...state, todos };
    },
  },
});

下面是深层嵌套的例子,应尽量避免。

app.model({
  namespace: ‘app‘,
  state: {
    a: {
      b: {
        todos: [],
        loading: false,
      },
    },
  },
  reducers: {
    add(state, { payload: todo }) {
      const todos = state.a.b.todos.concat(todo);
      const b = { ...state.a.b, todos };
      const a = { ...state.a, b };
      return { ...state, a };
    },
  },
});

二、Effect

示例:

app.model({
  namespace: ‘todos‘,
  effects: {
    *addRemote({ payload: todo }, { put, call }) {
      yield call(addTodo, todo);
      yield put({ type: ‘add‘, payload: todo });
    },
  },
});

Effects

put

用于触发 action 。

yield put({ type: ‘todos/add‘, payload: ‘Learn Dva‘ });

call

用于调用异步逻辑,支持 promise 。

const result = yield call(fetch, ‘/todos‘);

select

用于从 state 里获取数据。

const todos = yield select(state => state.todos);

错误处理

全局错误处理

dva 里,effects 和 subscriptions 的抛错全部会走 onError hook,所以可以在 onError 里统一处理错误。

const app = dva({
  onError(e, dispatch) {
    console.log(e.message);
  },
});

然后 effects 里的抛错和 reject 的 promise 就都会被捕获到了。

本地错误处理

如果需要对某些 effects 的错误进行特殊处理,需要在 effect 内部加 try catch 。

app.model({
  effects: {
    *addRemote() {
      try {
        // Your Code Here
      } catch(e) {
        console.log(e.message);
      }
    },
  },
});

异步请求

异步请求基于 whatwg-fetch,API 详见:https://github.com/github/fetch

GET 和 POST

import request from ‘../util/request‘;

// GET
request(‘/api/todos‘);

// POST
request(‘/api/todos‘, {
  method: ‘POST‘,
  body: JSON.stringify({ a: 1 }),
});

统一错误处理

假如约定后台返回以下格式时,做统一的错误处理。

{
  status: ‘error‘,
  message: ‘,
}

编辑 utils/request.js,加入以下中间件:

function parseErrorMessage({ data }) {
  const { status, message } = data;
  if (status === ‘error‘) {
    throw new Error(message);
  }
  return { data };
}

然后,这类错误就会走到 onError hook 里。

三、Subscription

subscriptions 是订阅,用于订阅一个数据源,然后根据需要 dispatch 相应的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。格式为 ({ dispatch, history }) => unsubscribe 。

异步数据初始化

比如:当用户进入 /users 页面时,触发 action users/fetch 加载用户数据。

app.model({
  subscriptions: {
    setup({ dispatch, history }) {
      history.listen(({ pathname }) => {
        if (pathname === ‘/users‘) {
          dispatch({
            type: ‘users/fetch‘,
          });
        }
      });
    },
  },
});

path-to-regexp Package

如果 url 规则比较复杂,比如 /users/:userId/search,那么匹配和 userId 的获取都会比较麻烦。这是推荐用 path-to-regexp 简化这部分逻辑。

import pathToRegexp from ‘path-to-regexp‘;

// in subscription
const match = pathToRegexp(‘/users/:userId/search‘).exec(pathname);
if (match) {
  const userId = match[1];
  // dispatch action with userId
}

四、router

Config with JSX Element (router.js)

<Route path="/" component={App}>
  <Route path="accounts" component={Accounts}/>
  <Route path="statements" component={Statements}/>
</Route>

详见:react-router

Route Components

Route Components 是指 ./src/routes/ 目录下的文件,他们是 ./src/router.js 里匹配的 Component。

通过 connect 绑定数据

比如:

import { connect } from ‘dva‘;
function App() {}

function mapStateToProps(state, ownProps) {
  return {
    users: state.users,
  };
}
export default connect(mapStateToProps)(App);

然后在 App 里就有了 dispatch 和 users 两个属性。

Injected Props (e.g. location)

Route Component 会有额外的 props 用以获取路由信息。

  • location
  • params
  • children

更多详见:react-router

基于 action 进行页面跳转

import { routerRedux } from ‘dva/router‘;

// Inside Effects
yield put(routerRedux.push(‘/logout‘));

// Outside Effects
dispatch(routerRedux.push(‘/logout‘));

// With query
routerRedux.push({
  pathname: ‘/logout‘,
  query: {
    page: 2,
  },
});

除 push(location) 外还有更多方法,详见 react-router-redux

五、dva配置

Redux Middleware

比如要添加 redux-logger 中间件:

import createLogger from ‘redux-logger‘;
const app = dva({
  onAction: createLogger(),
});

注:onAction 支持数组,可同时传入多个中间件。

history

切换 history 为 browserHistory

import { browserHistory } from ‘dva/router‘;
const app = dva({
  history: browserHistory,
});

去除 hashHistory 下的 _k 查询参数

import { useRouterHistory } from ‘dva/router‘;
import { createHashHistory } from ‘history‘;
const app = dva({
  history: useRouterHistory(createHashHistory)({ queryKey: false }),
});

六、工具

通过 dva-cli 创建项目

先安装 dva-cli 。

$ npm install dva-cli -g

然后创建项目。

$ dva new myapp

最后,进入目录并启动。

$ cd myapp
$ npm start

 

以上是关于Dva.js总结的主要内容,如果未能解决你的问题,请参考以下文章

Dva.js中Subscription的理解和用法

React工作记录三十一dva.js初识

003-and design-dva.js 知识导图-01-Reducer,Effect,Subscription,Router,dva配置,工具

002-and design-dva.js 知识导图-01JavaScript 语言,React Component

前端分层和框架

数组方法总结 常用数组方法总结 js的数组或对象常用方法总结