什么是dva
dva 使用 redux 和 redux-saga 来使你更好的操作数据流, 并且还内置了 react-router, 以及 fetch, 它可以说是一个轻量级的应用框架, 使你更加方便得编写React 代码!
初始化
要想使用dva, 我们需要创建一个dva实例
dva()
// 初始化dva
const app = dva({
history: createHashHistory({
basename: '' // 这里可以设置基本的路径,如果你最终项目部署位置不在根目录, 需要改变
})
})
初始化dva, 创建一个实例, 你可以操作一些内部封装的hock方法, 更多的配置
app.use()
你甚至可以使用一些插件来扩展 dva的 功能, 例如 使用 dva-loading, 我将在后面讲解这个插件的作用
import createLoading from 'dva-loading'
app.use(createLoading())
app.router()
你可以使用它来配置路由, 这里建议是通过一个文件来生成路由, 并且通过 dynamic 方法来生成动态路由, 更多你可以查看
import dynamic from 'dva/dynamic';
const UserPageComponent = dynamic({
app,
models: () => [
import('./models/users'),
],
component: () => import('./routes/UserPage'),
});
app.start()
你需要启动项目, 必须调用该方法, 它接受一个dom元素作为页面挂载的, 如果不传递, 将会返回JSX 元素的函数, 你可以使用它来放置到别的地方, 类似于你平时写一个App主组件一样, 例子中使用了国际化, 需要包裹主组件
// 传递dom
app.start('#root');
// 不传递
import { IntlProvider } from 'react-intl';
...
const App = app.start();
ReactDOM.render(<IntlProvider><App /></IntlProvider>, htmlElement);
Model
Model 是 dva 的核心功能, 它可以方便的操作管理数据状态, 它就是基于 redux 和 redux-saga 进行封装的, 如果你不熟悉 redux , 你可以查看这篇文章
namespace
model的命名空间, 同时也是他在全局 state 上的属性, 意思就是,它既是state中对应的key值也是我们创建model对应的名称, 我们在触发action 到 相应的 reducer 的时候, 需要使用到它, 它可以说是必须的
state
用于存放当前model中的state初始值, 需要注意的是,这里定义的值, 优先级低于在你创建dva实例通过 initialState属性 创建的值
看以下例子
const app = dva({
initialState: { count: 1 },
});
app.model({
namespace: 'count',
state: 0,
});
最终初始值将会为 1
reducers
接收当前state以及action, 里面是用于描述应该如何去修改state的函数, ==这里是用于同步修改state的时候使用到的==, 函数定义的格式应该为:(state, action) => newState 或者 [(state, action) => newState, enhancer], action 就是包含了 当前action的名称, 以及最终你传递的参数, 这个参数可以说是你最终想修改成state的值,或者用它来改变state的值

reducers: {
// 定义了一个名为 loginSuccess 的 reducers
loginSuccess(state, { payload }) {
return {
...state,
loggedIn: true,
message: '',
user: payload
};
}
}
effects
用于异步去修改state的数据, 它接受 action 以及 effects, effects 它是一个对象, 里面内置了不少方法

call
call 的作用处理异步, 就是因为有了它,我们才在effects 处理异步的一些操作, 它是一个函数, 第一个参数接受一个函数, 第二个参数接受该函数需要传递的参数, 你可以在这里发送一些ajax 请求
// call为请求的函数, payload就是传递的值
const { status, message, data } = yield call(login, payload);
pull
pull的作用在于触发action,而action又会触发对应的reducers, 从而达到state的更新, 试想一下, 当call 回来的数据后,我们想讲这个数据更新到state中, 此时pull 就可以帮我们实现这一点
yield put ({
type:'xx/jj',
payload:res
});
// xx 为对应model中的namespace的名称, jj 为对应 effects 和 reducers的方法名称(key)
需要注意的是, action 即可触发 effects 和 reducers, 所以尽量不要将取相同的名称, 先会找到effects 在找到 reducers, 如果有相同名称的情况下
select
用于从state中获取相关的数据,
// state是全局的state, data就是你需要的数据
const data = yield select(state=>state.data);
subscriptions
用于订阅一个数据源, 那么这个数据源可以是什么呢 ?
它可以是 当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等,
你可以当这些数据有所变化的时候, 触发对应的dispatch,
定义格式应为: ({ dispatch, history }, done) => unlistenFunction
subscriptions: {
setup({ history, dispatch }) {
return history.listen(({ pathname }) => {
if (pathname.indexOf('/sign/login') !== -1) {
// 执行某些逻辑
}
});
}
},
例如我们可以在路由变化时候, 执行某些逻辑, 或者触发dispatch