今天,我们来介绍@rematch/core
其他几篇:
react数据集中式管理第二篇--@reduxjs/toolkit
@rematch/core的使用教程
Rematch是在redux的基础上再次封装,使用rematch,我们就不需要再声明action类型、action创建函数、thunks配置;
如果你之前学过vuex,那你对这个不会陌生,因为模式基本上一样。
引入依赖: yarn add @rematch/core (这里1.0版本和2.0版本还有些不一样,后续会讲到)
在store.js文件里面引入rematch:
用 init 初始化store,里面的一些属性后面介绍;
// 文件路径: /store/index.js
import { init } from "@rematch/core";
import count from "./modules/count";
import user from "./modules/user";
import postsReducer from "./modules/postsSlice";
import { counterReducer } from "./modules/createReducer";
import createSagaMiddleware from "redux-saga"; // 引入redux-saga中的createSagaMiddleware函数
import rootSaga from "./saga.js"; // 引入saga.js
import listen from "./modules/middleware";
const sagaMiddleware = createSagaMiddleware();
// 用 init 初始化store
const store = init({
models: {
count,
user, // 引入 user 模块
},
plugins: [listen],
redux: {
devtoolOptions: {
maxAge: 500,
traceLimit: 500,
},
reducers: {
posts: postsReducer,
counter: counterReducer,
},
middlewares: [sagaMiddleware],
},
});
store.subscribe(() => {
// 监听store的变化,每次store改变就会触发
console.log("store", store);
});
window.store = store;
sagaMiddleware.run(rootSaga); // 执行rootSaga
export default store;
引入rematch之后我们怎样去定义一个store
首先我们先介绍init配置的models字段;
models:将你定义的各个模块store放入里面,比如count、user模块
那我们以定义user模块来举例,直接上代码:(代码里面有注释说明)
// store/modules/user.js
const user = {
state: {
name: '夜不语',
},
reducers: {
changeUser(state, name) { // state为当前模块的state;name是调用changeUser的第一个参数;可使用多个参数
console(state) // {name: '夜不语'}
return {...state, name} // 注意这里不能直接state.name = name修改值
}
},
// 定义的函数可以使用异步操作,比如 async await
effects: {
// name是调用updateName的第一个参数;rootState是所有模块的state;
// 若updateName('12', 10)两个参数,则updateName(name, rootState, number)第三个参数number则为10;其实第一个参数传对象就好了;
updateName(name, rootState) {
console.log(name, rootState);
this.changeUser(name) // 调用reducers的changeUser函数
}
}
}
export default user;
从上面代码可以看出,每个model有属于自己state、reducers、effects
1)state:存放模块状态的地方
2)reducers:改变store状态的地方;每个reducers函数都会返回一个对象为****最新的state;这里的函数必须为****同步函数;
3)effects:处理异步数据;但是不能修改state,但是能够调用reducers里面的函数去改变state,比如:this.changeUser(name)
看到这里rematch的state、reducers、effects和vuex的state、mutaition、action用法是不是非常相似;
接下来就是在其他地方获取该模块的state和修改state的值:
// UserContent.js
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import {connect} from 'react-redux';
// import { dispatch, getState } from '@rematch/core';
const UserContent = (props) => {
const {name} = useSelector(state => {
return {
name: state.user.name,
}
})
const dispatch = useDispatch()
const updateName = () => {
// props.updateName('张三')
// props.changeUser('张三')
// 就是直接dispatch.模块名.fn(); 其中模块名就是挂载在models上的,方法名就是该模块下你定义在reducers和effects里面的方法
dispatch.user.updateName('张三')
console.log(dispatch.user, "dispatch.user")
}
return (
<div>
<section className="posts-list">
<h2>UserContent</h2>
</section>
<section>
<div>connect的方式:{props.username}</div>
<div>hooks的方式:{name}</div>
<button type="button" onClick={() => updateName()}>
修改名称
</button>
</section>
</div>
);
};
const mapStateToProps = (state) => ({
username: state.user.name,
})
const mapDispatchToProps = (dispatch) => ({
// 可以调用定义的reducers和effects
updateName: dispatch.user.updateName,
changeUser: dispatch.user.changeUser
})
export default connect(mapStateToProps, mapDispatchToProps)(UserContent);
1)使用redux高阶组件connect将state、reducers、effects绑定到组件的props上;
export default connect(mapStateToProps, mapDispatchToProps)(UserContent);
使用:props.username; props.updateName('张三');
2)使用hooks来获取state和修改;
// 修改:就是直接dispatch.模块名.fn(); 其中模块名就是挂载在models上的,方法名就是该模块下你定义在reducers和effects里面的方法
// 获取:直接useSelector直接获取
3)用rematch提供的dispatch和getState
import { dispatch, getState } from '@rematch/core';
以上就是从rematch的引入到创建模块store的实例,是不是还ok;
接下来介绍一下init里面的配置:
init里面的配置:plugins
Plugins 用来自定义init配置或内部hooks,它能添加功能到你的Rematch设置当中来
就是你添加插件之后,每次 dispatch 都会执行插件的逻辑;添加插件的方式版本不同写法不一样,如代码所示;
关于plugins相关配置可查看:rematch.gitbook.io/handbook/ap… | rematchjs.org/docs/api-re…
// 该写法是 @rematch/core": ^1.1.0
export const listen = {
middleware(store) {
return (next) => (action) => {
const returnValue = next(action);
console.log(action, store, "listen");
// 每次 dispatch 时会触发这里
// do something 在这里做逻辑处理
return returnValue;
};
},
};
// 该写法是 @rematch/core": ^2.0.1
export const plugin = {
config: {},
exposed: {},
createMiddleware(rematchBag) {
return (store) => (next) => (action) => {
const returnValue = next(action);
console.log(action, store, "createMiddleware");
// 每次 dispatch 时会触发这里
// do something
return returnValue;
};
},
};
// store/index.js
const store = init({
.....
plugins: [listen, plugin], // 将插件挂载
.....
});
init里面的配置:redux
可以直接访问redux,不使用rematch/core封装的redux;
比如项目上之前使用@reduxjs/toolkit创建模块store,但是不想改成rematch模式;那就可以把之前的模块挂载到reducers上面就行了;
middlewares就是可以给你的store增加中间件,比如saga;
代码里面有说明:
redux: {
// 开发者配置
// 配置可查看:https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md
devtoolOptions: {
maxAge: 500, // number (>1) - 存储在历史树中的最大允许操作。达到 maxAge 后,最旧的操作将被删除。这对性能至关重要。默认为50
traceLimit: 500,
},
reducers: { // 允许传递 reducer functions;将redux模块挂载到这里
posts: postsReducer,
counter: counterReducer,
},
// 添加 middleware 中间件到你的 store
middlewares: [sagaMiddleware], // 中间件,加载sagaMiddleware
},
// redux其他配置可查看:https://rematch.gitbook.io/handbook/api-wen-dang/init-redux-api
还有其他redux的配置可以查看网上的,或者这里→ rematch.gitbook.io/handbook/ap…
最后个人觉得项目中使用哪种方式搭建redux可以根据实际项目来,简单容易上手的就挺不错的。