前言:

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

简介:

先看看rematch的官方介绍:

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

rematch是在redux的基础上再次封装后成果,在rematch中我们不用声明action类型、action创建函数、thuks、store配置、mapDispatchToProps、saga。如果你习惯使用vuex,那么你一定会喜欢上rematch的,因为rematch的写法和vuex基本一样。

一个简单的demo:

先看看我们的项目结构:

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

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

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);
 

    

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
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踩了才知道。

rematch:当你受不了redux繁琐写法的时候,是时候了解一波rematch了的更多相关文章

  1. Rematch Redux的替代品

    前言:Rematch和vuex很像. 文档:https://github.com/yurizhang/rematch 简介: 先看看rematch的官方介绍: Rematch是没有boilerplat ...

  2. React进阶篇(2) -- Redux

    前言 如果还不知道为什么要使用Redux,说明你暂时还不需要它. 三大原则 单一数据源 整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一 ...

  3. redux-simple 简化版的redux

    作为react的粉丝,当然要吐槽一下react组件通信问题.react的单向数据流是组件通信的一大阻碍,只允许父组件向子组件传值,子组件向父组件传值只能通过父组件向子组件传递回调函数实现.如果在深层次 ...

  4. listview--Java泛型应用之打造Android万能ViewHolder-超简洁写法

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010785585/article/details/52808656 转载请注明出处:http:// ...

  5. redux基础(1)

    redux ps:每个案例都是接着上一个案例写的 主要以案例讲解如何使用,具体概念请参考如下: 基本概念参考1 基本概念参考2 案例源码戳这里 一.Store.Action.Reducer简介 Sto ...

  6. rematch的基本用法

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

  7. 【React】Stateless Function

    React创建组件的时候,有3种写法: // 1. 传统写法 const App = React.createClass({}); // 2. es6 的写法 class App extends Re ...

  8. KnockoutJS 3.X API 第六章 组件(4) 自定义元素

    自定义元素提供了一种将组件注入视图的方便方法. 本节目录 介绍 例子 传递参数 父组件和子组件之间的通信 传递监控属性的表达式 将标记传递到组件中 控制自定义元素标记名称 注册自定义元素 备注1:将自 ...

  9. Python机器学习库scikit-learn实践

    原文:http://blog.csdn.net/zouxy09/article/details/48903179 一.概述 机器学习算法在近几年大数据点燃的热火熏陶下已经变得被人所“熟知”,就算不懂得 ...

随机推荐

  1. CDI services--Decorators(装饰器)

    1.Decorators装饰器综述 拦截器是一种强大的方法在应用程序捕捉运行方法和解耦.拦截器可以拦截任何java类型的调用. 这使得拦截器适合解决事务管理,安全性,以及日记记录. 本质上说,拦截器并 ...

  2. 关于mysql分组查询

    在mysql查询中,用到GROUP BY 根据某一字段分组之后,每组显示的结果都只有第一条,这样的结果通常不是我们想要的. GROUP_CONCAT('字段')   可以将每一组下面的这个字段所有的数 ...

  3. md5加密utils

    package cn.itcast.bos.utils;   import java.math.BigInteger; import java.security.MessageDigest; impo ...

  4. ORACLE 数据库管理

    [故障处理]ORA-12162: TNS:net service name is incorrectly specified 本文将给大家阐述一个因未设置系统环境变量ORACLE_SID导致ORA-1 ...

  5. javascript中计算两个时间日期间隔的天数

    <script>              /*                  计算两个日期的时间间隔天数              */              //时间字符串的格 ...

  6. java.lang.IllegalAccessError: org.apache.commons.dbcp.DelegatingPreparedStatement.isClosed()Z

    做spring和mybaits整合时出现的错误,让这个问题困扰了一早上,通过查资料终于把这个问题解决了 具体问题描述: java.lang.IllegalAccessError: org.apache ...

  7. Docker日志收集最佳实践

    传统日志处理 说到日志,我们以前处理日志的方式如下: · 日志写到本机磁盘上 · 通常仅用于排查线上问题,很少用于数据分析 ·需要时登录到机器上,用grep.awk等工具分析 那么,这种方式有什么缺点 ...

  8. AL32UTF8 and UTF8 and ZHS16GBK

    About AL32UTF8 ORACLE数据库字符集,即Oracle全球化支持(Globalization Support), 或即国家语言支持(NLS)其作用是用本国语言和格式来存储.处理和检索数 ...

  9. NetBeans远程调试Linux c++ 11项目

    NetBeans远程调试Linux c++ 11项目 由于好多原因,好久没有写博客了,随着c++ 11的普及率越来越高,开发c++ 项目的人也越来越多,可以说c++ 11 给了c++ 这门语言第二次生 ...

  10. [转载来之雨松:NGUI研究院之为什么打开界面太慢(十三)]

    本文固定链接: http://www.xuanyusong.com/archives/2799