rematch:当你受不了redux繁琐写法的时候,是时候了解一波rematch了

前言:html

前段时间学习完react后,恰好就接到公司一个react项目的迭代,顺便巩固一下前段时间的学习成果。项目使用的是redux+react-router,将全部的数据都放在redux中,异步处理数据使用redux-saga。因为是迭代项目,因此代码风格仍是沿用以前项目的写法,将全部的数据都放在redux中。写redux的时候心中默默的吐槽了无数次,特别是每次从服务端异步获取数据的时候心中都会默默的想 “我只是想实现从服务端取一个列表数据,而后保存在store中,为何须要引入redux-saga,而且引入后写法仍是很繁琐(虽然流程很清晰明了,可是须要进行大量的复制粘贴)” ,写着写着感受心态就快崩了 。后面通过同事的介绍,了解到有rematch这么一个更好用的js状态容器,终于能够脱离redux了。vue

 

简介:react

先看看rematch的官方介绍:vuex

Rematch是没有boilerplate的Redux最佳实践。没有多余的action types,action creators,switch 语句或者thunks。redux

rematch是在redux的基础上再次封装后成果,在rematch中咱们不用声明action类型、action建立函数、thuks、store配置、mapDispatchToProps、saga。若是你习惯使用vuex,那么你必定会喜欢上rematch的,由于rematch的写法和vuex基本同样。bash

 

一个简单的demo:react-router

先看看咱们的项目结构:异步

├── index.html ├── index.js        # 项目的入口
├── ....
└── store ├── index.js # 引入modules的各个模块,初始化store的地方 └── modules ├── count.js # count模块 └── info.js    # info模块

1. store/index.js,初始化一个store实例async

import { init } from '@rematch/core'; import count from './modules/count'; import info from './modules/info'; const store = init({ models: { count, info, } }) export default store;

   rematch提供 init()方法,返回一个store的实例。初始化store的时候rematch支持传入多个模块,在中、大型项目中能够根据业务的须要,拆分红多个模块,这样项目的结果就会变得清晰明了。函数

2. store/modules/count.js,编写count模块业务代码

const count = { state: { num: 1,
     type: 2 }, reducers: { increment(state, num1, num2) { // 从第二个变量开始为调用increment时传递进来的参数,后面依次类推,例如:dispatch.count.increment(10, 20)时, num1 = 10 , num2 = 20.
return {
          ...state, num: num1 } }, }, effects: { async incrementAsync(num1, rootState, num2) { // 第二个变量为当前model的state的值,num1为调用incrementAsync时传递进来的第一个参数,num2为调用时传递的第二个参数,后面依次类推。例如:dispatch.count.incrementAsync(10, 20)时,num1 = 10, num2 = 20 await
new Promise(resolve => setTimeout(resolve, 2000)); this.increment(num1); } } } export default count;

  事实上咱们的count模块就是一个对象,该对象包含三个属性:state、reducers、effects。

  state:存放模块状态的地方。

  reducers:改变store状态的地方,每一个reducers函数都会返回一个对象做为模块最新的state。reducers中的函数必须为同步函数,若是要异步处理数据须要在effects中处理。注意:只能经过在reducers的函数中经过返回一个新的对象来改变模块中state的值,直接经过修改state的方式是是不能改变模块的state的值。例:

 increment(state, num1) { state.num = num1  // 这样的写法是错误的
        },

  effects:处理异步数据的地方,好比:异步从服务端获取数据。注意:在effects中是不能修改模块的state,须要在异步处理完数据后调用reducers中的函数修改模块的state。

  rematch的state、reducers、effects和vuex的state、mutaition、action用法很是类似,在vuex中mutation修改model的state的值,action进行异步处理数据。

 3. 在组件中获取state和修改state的值

  有2种方法能够获取state和修改state:(1)使用redux的高阶组件connect将state、reducers、effects绑定到组件的props上。(2)使用rematch提供的dispatch和getState。

   (1)使用redux的高阶组件connect

    使用redux提供的高阶组件connect给App组件注册countState和countDispatch属性,其中countState对应的是count模块的state属性,countDispatch对应的是count模块的reducers和effects。在组件中使用this.props.countState和this.props.countDispatch就能够访问到count模块提供的state和reducers、effects了。

import React, {Component} from 'react'; import {connect} from 'react-redux'; class App extends Component { handleClick = () => { const { countDispatch } = this.props; countDispatch.increment(10) }; render() { const { countState } = this.props; return ( <div className="App" onClick={this.handleClick}> 当前num为{countState.num},点我num加10 </div>
 ); }; } const mapStateToProps = (state) => ({ countState: state.count }) const mapDispatchToProps = (dispatch) => ({ countDispatch: dispatch.count }) export default connect(mapStateToProps, mapDispatchToProps)(App);

  (2)dispatch和getState

    getState:rematch提供的getState方法返回整个store的state对象,若是要单独访问count模块的state,只须要 getState( ).count便可。

    dispatch:rematch提供的dispatch能够直接调用整个store中定义的reducers和effects。例:dispatch.count.increment(10) ,其中count为store中的一个model,increment方法为count模块中提供的一个reducers。调用effects的方法和调用reducers的方法同样。

import React, {Component} from 'react'; import { dispatch, getState } from '@rematch/core'; class App extends Component { handleClick = () => {
     console.log(getState().count); // {num: 1, a: 1} dispatch.count.increment(10) }; render() { let countState = getState().count; console.log(countState); return ( <div className="App" onClick={this.handleClick}> 当前num为{countState.num},点我num加10 </div> ); }; }
const mapStateToProps = (state) => ({ countState: state.count }) const mapDispatchToProps = (dispatch) => ({ countDispatch: dispatch.count }) export default connect(mapStateToProps, mapDispatchToProps)(App);
 

     

四、在一个model的reducers中的函数中触发另一个model的reducers中的函数  

  场景:A函数和B函数里面有大量类似的代码,这个时候咱们通常的作法都是将A、B函数的公共部分提取出来成一个公共函数,这样咱们就不须要在A函数和B函数中写大量类似的代码。假如在reducers中,咱们将A函数和B函数提取的公共函数C放在公共模块info的reducers中,A函数是在count模块的reducers中。在这种状况下咱们就须要在公共模块info的函数C执行完后调用count模块的A函数。

{  // count模块
 ... reducers: { ... 'info/addAge': (state, payload) => {  // payLoad的值为addAge传入的值10
 console.log(payload) // 10 return { ...state, num: 10 } } }, ... } { // info模块
 ... reducers: { addAge(state, num) { return { age: state.age + num.age, } } } ... }

  经过dispatch.info.addAge(10)调用info模块的addAge函数,当addAge函数执行完后会触发count模块的 ' info/addAge ' ,而且 ' info/addAge '的参数payload的值为调用info模块的addAge函数时传入的参数 10

 

 总结:

因为rematch的写法和vuex很类似,因此在接触rematch的时候以为很是熟悉,很好上手,具体有有哪些坑只有等下次项目中引入了rematch踩了才知道。

相关文章
相关标签/搜索