react数据集中式管理第四篇--@rematch/core

1,013 阅读5分钟

今天,我们来介绍@rematch/core

其他几篇:

react数据集中式管理第一篇--Redux初认识

react数据集中式管理第二篇--@reduxjs/toolkit

react数据集中式管理第三篇--redux-saga

@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直接获取

image.png

3)用rematch提供的dispatch和getState

import { dispatch, getState } from '@rematch/core';

image.png

以上就是从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可以根据实际项目来,简单容易上手的就挺不错的。