ifyour / learn-react

🤠 React learning notes
MIT License
6 stars 0 forks source link

Dva 核心概念理解 #7

Open ifyour opened 6 years ago

ifyour commented 6 years ago

What

Dva 是基于现有应用架构 (Redux + React-router + Redux-saga 等)的一层轻量封装.

How

image

Why

提高前端人员开发效率, 总结来讲有以下原因选择 Dva:

More

ifyour commented 6 years ago

一些操作实例

/**
 * 数据的增删改, todos 为例
 */

app.model({
  namespace: 'todos',
  state: [],
  reducers: {
    add(state, { payload: todo }) {
      // 直接拼接到空的 state 数组中
      return state.concat(todo)
    },
    remove(state, { payload: id }) {
      // 过滤出来不相等的, 其实就是删除指定 id
      return state.filter( todo => todo.id !== id)
    },
    update(state, { payload: updateTodo }) {
      return state.map(todo => {
        if (todo.id === updateTodo.id) {
          // 展开该 todo 用新的 todo 去覆盖掉原来的 todo
          return { ...todo, ...updateTodo }
        } else {
          return todo;
        }
      })
    },
  },
})
/**
 * Effect 异步操作实例
 */

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

// 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 实例 onError 的 hook
 */

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

/**
 * 错误处理: 本地处理
 * 对某些 effects 的错误进行特殊处理,需要在 effect 内部加 `try catch`
 */

app.model({
  effects: {
    *addRemote() {
      try {
        // Your Code Here
      } catch(e) {
        console.log(e.message);
      }
    },
  },
});
/**
 * 异步请求 (POST/GET) 统一错误处理
 */

function parseErrorMessage({ data }) {
  const { status, message } = data;
  if (status === 'error') {
    throw new Error(message);
  }
  return { data };
}
/**
 * 异步数据初始化
 * 场景: 当用户进入到 /users 页面时, 触发一个 action `/users/fetch` 加载用户数据
 */

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

/**
 * 异步数据初始化
 * 场景: 匹配比较复杂的 URL, 比如 `/users/:userId/search`
 *      推荐用 path-to-regexp 简化这部分逻辑
 */

import pathToRegexp from 'path-to-regexp';
app.model({
  //...
  subscriptions: {
    setup({ dispatch, history }) {
      history.listen(({ pathname }) => {
        const match = pathToRegexp('/users/:userId/search').exec(pathname);
        if (match) {
          const userId = match[1];
          // 使用 userid 来触发一些 action
        }
      })
    }
  }
  //...
})
/**
 * 基于 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,
  },
});
/**
 * Dva 配置多个中间件
 */

import createLogger from 'redux-logger';
const app = dva({
  onAction: createLogger(),
  // 或者 onAction: [mid1, mid2]
});

/**
 * Dva 配置路由实现方式
 */

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

/**
 * Dva 去除 hashHistory 下的 _k 查询参数
 */

import { useRouterHistory } from 'dva/router';
import { createHashHistory } from 'history';
const app = dva({
  history: useRouterHistory(createHashHistory)({ queryKey: false }),
});
# 全局安装 dva-cli 
$ npm i dva-cli -g

# 创建项目
$ dva new myapp

# 进入项目并启动
$ cd myapp && npm start

More