在React开发中TypeScript下如何正确使用react-rematch?
体验地址:暂无地址
rematch是对redux的二次封装,简化了redux是使用,极大的提高了开发体验。rematch仅仅是对redux的封装,没有依赖redux-saga,也没有关联react,因此其可以用在其他的视图库中,如vue等。
一、介绍
1. rematch的优点
1.省略了action types
不必再多次写字符串,使用model/method代替
2.省略了action creators
直接调用方法,不必再生产action type,使用dispatch.model.method代替
3.省略了switch语句
调用model.method方法,不必判断action type
4.集中书写状态,同步和异步方法
在一个model中使用state,reducers和effects来写状态,同步和异步方法
2. rematch的model
model中直接写state,reducers,effects,十分集中方便
export const count = {
state: 0, // initial state
reducers: {
// handle state changes with pure functions
increment(state, payload) {
return state + payload
}
},
effects: (dispatch) => ({
// handle state changes with impure functions.
// use async/await for async actions
async incrementAsync(payload, rootState) {
await new Promise(resolve => setTimeout(resolve, 1000))
dispatch.count.increment(payload)
}
})
}
3. rematch的dispatch
dispatch可以直接调用同步和异步方法,不必再发送action
import { init } from '@rematch/core'
import * as models from './models'
const store = init({
models,
})
export const { dispatch } = store
// state = { count: 0 }
// reducers
dispatch({ type: 'count/increment', payload: 1 }) // state = { count: 1 }
dispatch.count.increment(1) // state = { count: 2 }
// effects
dispatch({ type: 'count/incrementAsync', payload: 1 }) // state = { count: 3 } after delay
dispatch.count.incrementAsync(1) // state = { count: 4 } after delay
4. rematch的状态派发
依然使用redux的connect,mapStateToProps,mapStateToDispatch来派发状态和方法到子组件
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider, connect } from 'react-redux'
import store from './index'
const Count = props => (
<div>
The count is {props.count}
<button onClick={props.increment}>increment</button>
<button onClick={props.incrementAsync}>incrementAsync</button>
</div>
)
const mapState = state => ({
count: state.count
})
const mapDispatch = ({ count: { increment, incrementAsync }}) => ({
increment: () => increment(1),
incrementAsync: () => incrementAsync(1)
})
const CountContainer = connect(mapState, mapDispatch)(Count)
ReactDOM.render(
<Provider store={store}>
<CountContainer />
</Provider>,
document.getElementById('root')
)
二、使用
以上就是基本的使用教程,下面我们来看一个具体的例子,比如登录,此出登录模拟简单的登录,版本是ts版本,不使用加密:
1. 创建和初始化数据仓库
首先新建models文件夹,存放下面出现的这些文件。
在login.ts中写入如下代码:
import { createModel } from '@rematch/core'
import Request from '@/request/Request';
import {
DOMAIN, LOGIN_URL
} from '@/config/api.config';
import { REQUEST_SUCCESS } from '@/config/config';
export interface StateType {
userInfo: any
}
export interface IAction{
username:string,
password:string,
callback?:Function
}
export const login = createModel<StateType>()({
state: {
userInfo: null
}, // initial state
reducers: {
setState(state, payload: any) {
return { ...state, userInfo: payload }
}
},
effects: (dispatch) => ({
async login(payload: IAction, rootState) {
const response = await new Request({
api: LOGIN_URL,
method: 'POST',
data: {
username:payload.username, password:payload.password
}
}).fetch();
if (response.code === REQUEST_SUCCESS) {
this.setState(response.data);
}
payload?.callback && payload?.callback(response);
},
}),
});
在modles.ts下面写入如下代码,作为多个的公共入口:
import { Models } from '@rematch/core'
import { login } from './login'
export interface RootModel extends Models {
login: typeof login
}
export const models: RootModel = {
login
}
在store.ts里面进行初始化,当然可以将这个文件单独分离成store文件夹,方便管理,最后导入路径自己对应即可:
import { init, RematchDispatch, RematchRootState } from '@rematch/core';
import { models, RootModel } from './models';
import { composeWithDevTools } from 'redux-devtools-extension';
import createLoadingPlugin from '@rematch/loading';
import updatedPlugin from '@rematch/updated';
const updated = updatedPlugin();
const loading = createLoadingPlugin({ asNumber:false });
export const store = init({
models,
plugins: [updated],
redux:{
devtoolOptions: composeWithDevTools,
}
})
export type Store = typeof store
export type Dispatch = RematchDispatch<RootModel>
export type RootState = RematchRootState<RootModel>
2. 装载数据仓库
这里采用react-redux提供的Provider提供器来共享store,如下代码:
import React from 'react';
import ReactDOM from 'react-dom';
import '@/index.less';
import App from '@/App';
// import { ConfigProvider } from 'antd';
import { Provider } from 'react-redux';
import { store } from '@/models/store';
ReactDOM.render(
// <ConfigProvider locale={zhCN}> //antd国际化配置
<Provider store={store}>
<App />
</Provider>
// </ConfigProvider>,
,
document.getElementById('root')
);
3. 使用
此出可以使用官方默认提供的方式进行暴露在props上面的方法进行使用,此出采用react-redux提供的hooks进行使用,采用useSelector和useDispatch,如下代码:
import { useSelector, useDispatch } from 'react-redux' //引入
const userState = useSelector((state: RootState) => state.login);//取得store下面的login model,后面就可以userState.userInfo取得userInfo里面的内容了
const dispatch = useDispatch() as Dispatch; //取得dispatch
const onLoginFinish = useCallback(
(values: any) => {
setLoading(true);
dispatch.login.login({
username: values.username, password: values.password, callback: (res: any) => {
if (res.code != 0) {
message.error(res.msg);
setLoading(false);
} else {
localStorage.setItem(USER_TOKEN_NAME, res.token);
message.success(res.msg);
setTimeout(() => {
setLoading(false);
history.push('/');
}, 1500);
}
}
})
},
[loading],
)
以上还存在ts模式下,配置loading会说dispatch of undefined,有大佬知道是什么问题的,可以给我发邮件进行交流,如果觉得对你有帮助的话,支持一下呗!
