微日志_免费提供日志记录|作品展示|学习教程|免费日记

在React开发中TypeScript下如何正确使用react-rematch?

教程 rematch react 阅读:204

体验地址:暂无地址

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,有大佬知道是什么问题的,可以给我发邮件进行交流,如果觉得对你有帮助的话,支持一下呗!