ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

@rematch/core——dispatch的简化版

2022-02-28 21:00:09  阅读:425  来源: 互联网

标签:count 简化版 dispatch rematch state num 模块 reducers


rematch是对redux的二次封装,简化了redux是使用,极大的提高了开发体验。rematch仅仅是对redux的封装,没有依赖redux-saga,也没有关联react,因此其可以用在其他的视图库中,如vue等。

rematch-官方文档

1 一个简单的demo

项目结构

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

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

import { init } from '@rematch/core';
import count from './modules/count';

const store = init({
    models: {
        count
    }
})

export default store;

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

1.2. rematch的model: store/modules/count.js

model中直接写state,reducers,effects,十分集中方便

const count = {
    state: {
        num: 1
    },
    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) { 
            /*
                第二个变量rootState, 为当前model的state的值

                第一个变量num1, 第三个变量num2分别, 调用incrementAsync时传递进来的第一个参数, 第二个参数,后面依次类推。
                例如:dispatch.count.incrementAsync(10, 20)时,num1 = 10, num2 = 20
            */
            await new Promise(resolve => setTimeout(resolve, 2000));
            this.increment(num1);
        }
    }
}

export default count;

effects 也可以是方法, count模块可以改写成

const count = {
    state: {
        num: 1
    },
    reducers: {
        increment(state, num1, num2) {         
              return  {
          ...state,
                num: num1
            }
        },
    },
    effects: (dispatch) => ({
        async incrementAsync(num1, rootState, num2) {
            await new Promise(resolve => setTimeout(resolve, 2000));



            // 方式一
            // this.increment(num1); 

            // 方式二
            dispatch.count.increment(num1)

        }
    })
}

export default count;
  • 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进行异步处理数据。

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

有2种方法可以获取state和修改state:

(1)使用redux的高阶组件connect将state、reducers、effects绑定到组件的props上。

使用redux提供的高阶组件connect给App组件注册countState和countDispatch属性,其中countState对应的是count模块的state属性,countDispatch对应的是count模块的reducers和effects。在组件中使用this.props.countStatethis.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)使用rematch提供的dispatch和getState。

getState:rematch提供的getState方法返回整个store的state对象,如果要单独访问count模块的state,只需要 getState().count即可。

dispatch:rematch提供的dispatch可以直接调用整个store中定义的reducers和effects

// reducers
dispatch({ type: 'count/increment', payload: 1 }) // state = { count: 1 }
dispatch.count.increment(1)                       // state = { count: 2 }// 其中count为store中的一个model,

// effects
dispatch({ type: 'count/incrementAsync', payload: 1 }) // state = { count: 3 } after delay
dispatch.count.incrementAsync(1)                       // state = { count: 4 } after delay

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;

        return (
            <div className="App" onClick={this.handleClick}>
                当前num为{countState.num},点我num加10
            </div> 
        );
    };
}

1.4. 在一个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 
            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

2. rematch的优点

2.1. 省略了action types

不必再多次写字符串,使用model/method代替

2.2.省略了action creators

直接调用方法,不必再生产action type(原版dispatch方法返回{type, payload}),使用dispatch.model.method代替

2.3.省略了switch语句

调用model.method方法,不必判断action type ( 原本reduces中)

2.4.集中书写状态,同步和异步方法

在一个model中使用state,reducers和effects来写状态,同步和异步方法

标签:count,简化版,dispatch,rematch,state,num,模块,reducers
来源: https://www.cnblogs.com/qiqi715/p/15947535.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有