简单回顾一下官网rematch 使用
第一步:Init 初始化
init 用来配置你的 reducers, devtools & store。
import { init } from '@rematch/core'
import * as models from './models'
const store = init({
models,
})
export default store
第二步:配置Models
该model促使state, reducers, async actions 和 action creators 放在同一个地方。是不是很方便
const delay = (time) => new Promise(resolve => setTimeout(() => resolve(), time));
// count model
export const count = {
// 该model的初始state
state: 0,
// 存放纯函数,用于更新state
reducers: {
addBy(state, payload) {
return state + payload
},
reduceBy(state, payload) {
return state - payload
}
},
// 副作用函数,可以异步处理action
effects: (dispatch) => ({
async addByAsync(payload, state) {
await delay(1000)
dispatch.count.addBy(1)
},
async reduceByAsync(payload, state) {
await delay(1000)
dispatch.count.reduceBy(1)
}
})
};
Step 3: Dispatch
dispatch 是我们如何在你的model中触发 reducers 和 effects。 Dispatch 标准化了你的action,而无需编写action types 或者 action creators。
import { dispatch } from '@rematch/core'
// state = { count: 0 }
// 调用方式, 这里需要注意如果使用rematch提供的loadPlugin插件,需要使用
// dispatch[model][action](payload)的方式
dispatch({ type: 'count/addBy', payload: 1 }) // state = { count: 1 }
dispatch.count.addBy(1) // state = { count: 2 }
Step 4: View
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider, connect } from 'react-redux'
import store from './index'
const Count = props => (
<div>
<h1>数字: {props.count}</h1>
<button onClick={props.addByOne}>增加1</button>
<button onClick={props.addByOneAsync}>异步 增加1</button>
<button onClick={props.reduceByOne}>减少1</button>
<button onClick={props.reduceByOneAsync}>异步 减少1</button>
</div>
)
const mapState = state => ({
count: state.count
})
const mapDispatch = ({ count: { addBy, addByAsync, reduceBy, reduceByAsync }}) => ({
addByOne: () => addBy(1),
addByOneAsync: () => addByAsync(1),
reduceByOne: () => reduceBy(1),
reduceByOneAsync: () => reduceByAsync(1)
});
const CountContainer = connect(mapState, mapDispatch)(Count)
ReactDOM.render(
<Provider store={store}>
<CountContainer />
</Provider>,
document.getElementById('root')
)
从这里我们可以看到初始化入口为init 在源码中init 函数就是生成store的
import {createReduxStore, prepareModel, enhanceModel, createEffectsMiddleware} from './reduxStore'
function createRematchBag (config) {
const models = config.models;
const modelsBag = Object.keys(models).map(modelName => ({
name: modelName,
reducers: {},
...models[modelName]
}))
return {
models:modelsBag,
reduxConfig: {
reducers: {}, // 纯函数
middlewares: [], // 中间件
},
effects: {},
}
}
/**
* 该函数被调用去设置Rematch。返回store。
* @param {Object} config
* @returns
*/
function createRematchStore(config) {
// 存储重要的值
const bag = createRematchBag(config)
console.log('bag',bag)
bag.reduxConfig.middlewares.push(createEffectsMiddleware(bag))
// 将redux中createStore函数中的返回值
const reduxStore = createReduxStore(bag)
let rematchStore = {
...reduxStore,
name: config.name
}
// 处理models文件中reducers事件,生成store.dispatch[modelName][actionName]
bag.models.forEach((model) => prepareModel(rematchStore, model))
// 处理models文件中effects中的函数,生成store.dispatch[modelName][actionName]
bag.models.forEach((model) => enhanceModel(rematchStore, bag, model))
return rematchStore
}
/**
* 入口函数
* @param {Object} initConfig 注册models {models: {[string]: model}}
* @returns {Object} 返回store
* { @@observable: ƒ observable()
dispatch: action => {…}
getState: f getState()
name: "Rematch Store 0"
replaceReducer: ƒ replaceReducer(nextReducer)
subscribe: ƒ subscribe(listener)}
*/
export const init = (initConfig) => {
let count = 0
const config = {
name: initConfig.name ?? `Rematch Store ${count}`,
models: initConfig.models || {},
}
return createRematchStore(config)
}
export default {
init,
}
reduxStore.js
import * as Redux from 'redux'
/**
*
* @param {Object} bag
* @param {Object} model
*/
export const createModelReducer = (bag, model) => {
const modelReducers = {}
const modelReducerKeys = Object.keys(model.reducers)
modelReducerKeys.forEach((reducerKey) => {
modelReducers[`${model.name}/${reducerKey}`] = model.reducers[reducerKey]
})
// 定义reducer
const combinedReducer = (state = model.state, action) => {
if (action.type in modelReducers) {
return modelReducers[action.type](state, action.payload)
}
return state
}
// 生成命名空间:reducer对象
bag.reduxConfig.reducers[model.name] = combinedReducer
}
/**
* 调用Redux.createStore方法,
* createStore(reducer, initState, compose(appleMiddleware(...middlewares))
* @param {Object} bag
* @returns
*/
export const createReduxStore = (bag) => {
bag.models.forEach((model) => createModelReducer(bag, model))
const middlewares = Redux.applyMiddleware(...bag.reduxConfig.middlewares)
return Redux.createStore(Redux.combineReducers(
bag.reduxConfig.reducers,
),{}
,middlewares
)
}
// 处理models中的reducers
export const prepareModel = (rematchStore, model) => {
const modelDispatcher = {}
rematchStore.dispatch[model.name] = modelDispatcher
const modelReducersKeys = Object.keys(model.reducers)
modelReducersKeys.forEach((reducerName) => {
rematchStore.dispatch[model.name][reducerName] = createActionDispatcher(
rematchStore,
model.name,
reducerName
)
})
}
// 处理models中的effects
export const enhanceModel = (rematchStore, bag,model) => {
const modelDispatcher = rematchStore.dispatch[model.name] || {}
let effects = {}
if (model.effects) {
effects =
typeof model.effects === 'function'
? (model.effects)(rematchStore.dispatch)
: model.effects
}
const effectKeys = Object.keys(effects)
effectKeys.forEach((effectName) => {
bag.effects[`${model.name}/${effectName}`] =
effects[effectName].bind(modelDispatcher)
modelDispatcher[effectName] = createActionDispatcher(
rematchStore,
model.name,
effectName,
)
})
}
// 这里将effects异步调用的逻辑放在中间件中处理
// 中间件结构 (store)=> (next) => (action)
export const createEffectsMiddleware = (bag) => {
return (store) =>
(next) =>
(action) => {
if (action.type in bag.effects) {
next(action)
// 调用
// addByAsync(payload, state) {
// },
return (bag.effects)[action.type](
action.payload,
store.getState(),
)
}
return next(action)
}
}
const createActionDispatcher = (rematch,
modelName,
actionName,
) => {
return (payload) => {
const action = { type: `${modelName}/${actionName}` }
if (typeof payload !== 'undefined') {
action.payload = payload
}
// 最终调用
return rematch.dispatch(action)
}
}
这里可以看看rematch设计 重新思考redux