这比较适合看过redux但看了跟没看一样的同学,帮助记忆理清里面的基础知识

一. Redux

1. Store

Store是保存数据的地方,可以把它看做一个容器。整个应用只能有一个Store。

Redux提供createStore这个函数生成store

import { createStore } from 'redux';
const store = createStore(fn);// store也可以接受第二个参数:state的初始值,他会覆盖reducer的state参数中的默认初始值
const store = createStore(fn, initState);

2. State

当你想拿到某个时刻的数据state时,需要生成对应的store快照。

const state = store.getState();

3. Action

由于用户触碰不到代码(State),只能通过触碰View来通知代码服务(store)改变State,这个由View发起的通知就是Action。

Action是一个对象,其中type是必须的,表示Action的名称。其他属性可以自由设置。

const action = {type: "ADD",payload: "data"
}

可以理解为,要触发一个ADD行为,携带的参数是payload

3.3 Action Creator

类似于工厂模式,Action肯定会有很多种消息,因此可以写一个Action Creator来生产一个Action

function AddCreator(text) {return {type: "ADD",payload: text}
}

4. Dispatch

你可以将action理解为一个通知单,那么View如何发出这个通知单给代码服务(store)呢,就是通过dispatch

只要给dispatch传入一个action参数,View就把通知单发出去了!

import { createStore } from 'redux';
const store = createStore(fn);const action = {type: "ADD",payload: "data"
}store.dispatch(action);

5.Reducer

View把通知单传给代码服务后,代码服务(Store)总要根据action中的内容去进行相应的处理的。reducer就是用来识别action并进行相应处理的处理器。他接收当前State和Action作为参数,返回一个新的State。

//其实就是先去判断action要执行哪个操作,再把对应的state更新并返回
function reducer = (state = initState, action) => {switch(action.type) {case 'ADD':return state + action.payload;default:return state}
}

注意这个处理器是store的,也就是说,store的创建是伴随reducer参数来初始化的。

import { createStore } from 'redux';
const store = createStore(reducer);

6. Subscribe

Store也提供了subscribe方法来设置监听函数,一旦State发生变化,就会自动执行这个函数。

store.subscribe返回一个函数,调用这个函数可以解除监听。

const listener = function() {console.log(store.getState())
}
let unsubscribe = store.subscribe(listener);// 解除监听
unsubscribe();

过度------------简易使用

你知道的,毕竟store不是react组件中的state,store中state的更新并不会让View也同时变化,你需要手动调用render重新渲染。

const Counter = ({ value, onIncrement, onDecrement }) => (<div><h1>{value}</h1><button onClick={onIncrement}>+</button><button onClick={onDecrement}>-</button></div>
);const reducer = (state = 0, action) => {switch (action.type) {case 'INCREMENT': return state + 1;case 'DECREMENT': return state - 1;default: return state;}
};const store = createStore(reducer);const render = () => {ReactDOM.render(<Countervalue={store.getState()}onIncrement={() => store.dispatch({type: 'INCREMENT'})}onDecrement={() => store.dispatch({type: 'DECREMENT'})}/>,document.getElementById('root'));
};render();
// 通过监听state的改变来更新视图
store.subscribe(render);

7. 中间件

当我们想要在store的整个流程中添加一些其他功能时,我们该往哪里添加?

处理流程中涉及逻辑进程的主要就是dispatch和reducer了,但reducer要求是纯函数,不能涉及副作用,那只能在dispatch中做手脚了。

先看一下想添加一个日志功能,并将更新后的state打印出来该如何实现:

let next = store.dispatch;
store.dispatch = function changeDispatch(action) {console.log('dispatching', action);next(action);console.log('next state', store.getState());
}

上面对store.dispatch进行了改造,添加了一些功能,这就是中间件的雏形。中间件其实就是一个函数。

7.1 applyMiddlewares()

Redux提供了原生方法applyMiddlewares来加入中间件,增强store.dispatch的功能。

他可以将中间件组成一个数组,然后依次执行。

import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();const store = createStore(reducer,initial_state,applyMiddleware(logger, ...otherMiddlewares)
);

8. 如何处理异步操作

Action发出后,过一段时间再执行Reducer,这就是异步。

那么Reducer作为纯函数肯定是不可以在这里添加处理异步逻辑的,那么就得在store.dispatch中做手脚了。

想一想,如果不能同步的进行dispatch(异步) -> reducer,那不如将dispatch分为两步走,dispatch(异步获取) -> dispatch(同步发送action) -> reducer

// 操作发起时的 Action
// 操作成功时的 Action
// 操作失败时的 Action

具体如何改造多次的dispatch可以使用redux-thunk或者redux-promise,他们处理后,dispatch可以接受不同的参数,不再局限于action对象。

二. React-Redux

回忆下之前的Redux,state更新时我们需要设置监听函数实时re-render才能更新View,想要在其他组件中使用store都得引入一下。

React-Redux解决了上述的痛点:

  • 提供Provider把state注入全局,这样子组件就不用单独引入了
  • 响应式。无需我们手动监听,state的更新会自动帮我们更新View
  • 通过connnct把state和dispatch注入到当前组件的props上

1. Provider

React-Redux提供了组件,使得整个app能够访问到store中的数据,Provider是用context封装的。

2. connect

React-Redux将组件分为两种,一种是UI组件,另一种是容器组件。

UI组件只通过接受props来显示UI,容器组件负责管理数据和业务逻辑(也就是承接state和dispatch)

React-Redux提供一个connect方法能够把组件和store连接起来,把state、dispatch方法都放入到当前组件上,同时是state变成响应式。其实就是一个高阶组件包装了一下我们写的UI组件。

// index.js
import React from 'react';
import ReactDom from "react-dom"
//引入Provider
import {Provider} from "react-redux";import Counter from "./counter/ReactReduxCounter";import store from "./redux/basic/store"ReactDom.render(<Provider store={store}><Counter></Counter></Provider>,document.getElementById("root")
)

我们看到通过用<Provider/>来包装我们真正的reactDOM,就可以让里面所有的子组件都使用store了。

注意:用到store的子组件应该是通过connect包装后的。

// Counter.js
import React, { Component } from 'react';
import {connect} from "react-redux"//子组件
class Counter extends Component {//方法调用后自动更新数据increment=()=>{this.props.increment()}decrement=()=>{this.props.decrement()}render() {return (<div><div>{this.props.num}</div><button onClick={this.increment}>点我+1</button><button onClick={this.decrement}>点我-1</button></div>);}
}//该函数作为connect的第一个参数,能拿到state
//映射state到组建的props上
function mapStateToProps(state){return {num:state.counter}
}//该函数作为connect的第二个参数,能拿到dispatch
//映射dispatch方法到组建的props上
function mapDispatchToProps(dispatch){return {increment(){dispatch({type:"increment"})},decrement(){dispatch({type:"decrement"})}}
}//connet函数执行返回一个高阶组件
//调用这个高阶组件,传入当前组件Counter作为参数,返回一个增强的Counter组件
//这个增强的组件props里有store的state和dispach方法
export default connect( mapStateToProps , mapDispatchToProps )(Counter)
/// store.js
import { createStore } from "redux"const defaultState={counter:0
}//纯函数
let reducers =(state = defaultState ,action)=>{switch (action.type){case "increment":console.log("increment")return {counter:state.counter+1}case "decrement":return {counter:state.counter-1}default :return state }
}
const store = createStore(reducers)
export default store

3. mapStateToProps()和mapDispatchToProps()

注意到,上述connect()中传递了两个参数:mapStateToProps()和mapDispatchToProps()。

通过观察connect源码(下一节)发现,他是利用了context封装了一个高阶组件,在封装过程中,会调用上述两个方法,把store中的state和dispatch取出来放到子组件的props里。这样我们在编写组件的时候,就可以无感知的调用state和dispatch了。

  • mapStateToProps

    • 他是一个函数,接受state作为参数,返回一个对象,这个对象是你想从state中取出的数据

    • const mapStateToProps = (state) => {return {counter: state.counter}
      }
      
  • maoDispatchToProps

    • 他是一个函数,接受dispatch和ownProps(容器组件的props)两个对象,返回一个对象,这个对象中的值应该是一个包含可以触发dispatch的方法。

    • const mapDispatchToProps = (dispatch, ownProps) => {return {increment(num) {dispatch({type: "increment",payload: num})}}
      }
      

4. connect高阶组件的大致实现

function connect(mapStateToProps, mapDispatchToProps) {return function(WrappedComponent) {class Connect extends React.Component {componentDidMount() {// 组件加载完成后订阅store变化,如果store有变化则更新UIthis.unsubscribe = this.context.store.subscribe(this.handleStoreChange.bind(this));}componentWillUnmount() {// 组件销毁后,取消订阅事件this.unsubscribe();}handleStoreChange() {// 更新UIthis.forceUpdate();}render() {return (<WrappedComponent{...this.props}{...mapStateToProps(this.context.store.getState())} // 参数是store里面的数据{...mapDispatchToProps(this.context.store.dispatch)} // 参数是store.dispatch/>);}}Connect.contextTypes = {store: PropTypes.object};return Connect;};
}

5. React-Redux的hook版

可能我们觉得每次都要用connect封装一下组件太麻烦了,还要写mapStateToProps和mapDispatchToProps,react-redux为我们提供了一些hooks,比如常用的useSelector和useDispatch。

  • useSelector接收两个参数:selector和equalityFn。第一个参数是一个函数以获取你想要的state,第二个可选参数也是个函数,用于比较状态是否发生改变,如果函数执行结果为false就表示状态发生改变,组件将重新渲染。
  • useDispatch直接调用可获得dispatch
import { useSelector, useDispatch } from 'react-redux'const Home = (props) => {const dispatch = useDispatch();const number = useSelector(state => state.number);const handleClick = () => {dispatch({type: 'ADD',payload: 1})}return (<h2>{number}</h2><button onClick={handleClick}/>)
}

6. Redux和React-Redux的关系

依初初初学者短见,我们想要在React项目中使用共享数据时,使用的store都是通过Redux提供的createStore创建的store。React-Redux只是帮我们封装了一些方法,以帮助我们在子组件中更便利的使用state和dispatch等。

三. Rematch

如果说React-Redux是在Redux的基础上帮助子组件更便捷的使用state和dispatch。

那Rematch则是在和React-Redux搭配基础上帮我们更具封装性的创建store,加上更便利的使用state和dispatch。

1. 创建store

之前我们是通过redux的createStore的方法来创建store。

import { createStore } from 'redux';
const store = createStore(reducer, initState);

如果还想要添加一些异步处理,那可能还要加入中间件,reducer也变得很复杂。

而Rematch提供了init可以让我们把initState、reducers、异步处理方法封装在一起。

// store.js
import { init } from '@rematch/core';const count = {state: 0,reducers: {increment: (state, payload) => state + payload,decrement: (state, payload) => state - payload},effects: {  // 带有异步处理数据的reducerasync incrementAsync(payload) {await func();this.increment(payload);}}
}export const store = init(count);

如果到此为止,你可以用上述生成的store正常的配合react-redux的provider、connect去使用他。

2. 模块化

rematch建议我们将数据分类保存到models文件夹下的不同的文件里。最后在models/index.js中统一导出。

例如:

  • models/count.js
  • Models/user.js
// models/index.js
export { default as count } from './count'
export { default as user } from './user'
// store.js
import { init } from '@rematch/core'
import * as models from './models'export const store = init({models})

于是我们在每个组件上,可以直接引入store来取到想要的某个模块中的store和dispatch

// counter.js
import { store } from './store.js'const counter = () => {const { counter, user } = store.getState();const add = store.dispatch.counter.add;const changName = store.dispatch.user.changeName;const handleClick = () => {add({type: 'ADD',payload: 1})}return (<h2>{counter.number}</h2><h2>{user.name}</h2><button onClick={handleClick}/>)
}

但注意,以上state不是响应式的,也就是说触发dispatch改变state并不会让视图更新,我们依然需要结合react-redux中的connect或者hook来让其变成响应式。

由redux到react-redux再到rematch相关推荐

  1. React+Redux系列教程

    2019独角兽企业重金招聘Python工程师标准>>> 参考项目:https://github.com/lewis617/react-redux-tutorial 参考项目下载地址: ...

  2. React + Redux + Express + Mongodb 零基础开发完整大型商城网站视频教程(97 个视频)

    React + Redux + Express + Mongodb 零基础开发完整大型商城网站视频教程(97 个视频) mern 架构零基础开发完整电商网站 React + Redux + Expre ...

  3. React+Redux开发实录(一)搭建工程脚手架

    React+Redux开发实录(一)搭建工程脚手架 React+Redux开发实录(二)React技术栈一览 搭建工程脚手架 准备工作 安装node 安装git 安装一款前端IDE 推荐VSCode, ...

  4. 基于 react, redux 最佳实践构建的 2048

    前段时间 React license 的问题闹的沸沸扬扬,搞得 React 社区人心惶惶,好在最终 React 团队听取了社区意见把 license 换成了 MIT.不管 React license ...

  5. Redux 进阶 - react 全家桶学习笔记(二)

    注:这篇是17年1月的文章,搬运自本人 blog... https://github.com/BuptStEve/... 零.前言 在上一篇中介绍了 Redux 的各项基础 api.接着一步一步地介绍 ...

  6. 一个 react+redux 工程实例

    在前几天的一篇文章中总结部分提到了学习过程中基础的重要性.当然,并不是不支持大家学习新的框架,这篇文章就分享一下react+redux工程实例. 一直在学习研究react.js,前前后后做了几次分享. ...

  7. 最近在搞react redux react-router等,

    React: 我查了英文官网,中文官网,转了社区,对我这样的菜鸟而言,看是看懂了,主要是怎么把项目架起来... 先来说下学习心得: 鄙人拙见:看了大众点评的实战项目,之前也看了小码哥的react na ...

  8. React Redux: 从文档看源码 - Components篇

    注:这篇文章只是讲解React Redux这一层,并不包含Redux部分.Redux有计划去学习,等以后学习了Redux源码以后再做分析 注:代码基于现在(2016.12.29)React Redux ...

  9. 【温故知新】—— React/Redux/React-router4基础知识独立团Demo

    前言:React专注View层,一切皆组件:全部使用ES6语法,最新版本为React16. Redux是专注于状态管理的库,和react解耦:单一状态,单向数据流.[独立团github地址] 一.Re ...

  10. 实例讲解基于 React+Redux 的前端开发流程

    前言:在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 star 数达 42000 +,超过了 jquery 的 39000+,也即将超过前几年比较火的an ...

最新文章

  1. 关键词优化一定要从正规渠道入手
  2. delphi 调用php接口_新浪图床 API 接口调用与请求方法详细教程
  3. PHP 与Python 读取大文件的区别
  4. 易语言网盘服务器源码_使用使用rclone挂载OneDrive到服务器
  5. vue组件一直注册不了_【报Bug】现在究竟支不支持Vue.use内注册组件
  6. java速学_5分钟快速入门Java,不看真的可惜了
  7. java中对象字节数_JAVA中求解对象所占字节大小
  8. python 字典处理_Python 6 个字典操作你必须知道
  9. SWOT分析法(态势分析法)
  10. 互联时代如何真正支持与实现数据经济
  11. C语言实现—学生成绩管理系统(Linux下运行)
  12. java iplimage 头文件_在javacv中将IplImage转换为Mat
  13. RISC-V MCU 智能语音物联网家居控制系统
  14. React组件化开发
  15. linux下好用的ftp,linux好用的ftp客户端
  16. 诛仙手游 法宝属性道法性价比
  17. android7.0 root教程,小米4S(全网通 安卓7.0)一键ROOT详解教程,看教程ROOT
  18. oracle 11g crsd ocssd,[Oracle 11g r2(11.2.0.4.0)]集群守护进程gipc介绍
  19. redhat oracle环境变量配置文件,Redhat7.2(7.1)下oracle8.17的安装手册-数据库专栏,ORACLE...
  20. CSDN 下载 版块问题解决日志

热门文章

  1. 浅谈阿里妈妈前景和模式
  2. 计算机毕业设计(36)java毕设作品之新冠疫苗预约系统
  3. 智能优化方法——产生与发展
  4. “区块链”究竟是什么鬼
  5. java instanceof性能差_在J中使用instanceof的性能影响
  6. java实现第二届蓝桥杯四方定理
  7. 更新!Python文献超级搜索工具,可关键词搜索并批量下载!
  8. 【英语:基础进阶_正式场景表达】F5.时事热点必备口语
  9. 为什么你写博客时感觉很困难?
  10. nodeJS入门例子一—插件(Addons)