react-redux 懒人教程

3,322 阅读6分钟

书接上回 《redux懒人教程》,我们已经学会了使用redux管理混乱的全局状态,下面我们一起看看redux是怎么帮助我们管理react应用的状态的。

react面临什么问题

我们先捋一捋react的一些基础概念,看看在什么情况下我们才需要引入redux。

react这样的前端框架的功能一言概括就是实现了数据和UI的实时映射。开发者只需要通过react组件管理数据,当数据变化时,react会让其映射的UI实时更新。而组件的数据主要是两个:state和props。props是父组件传递过来的数据,state是组件自身管理的数据,它又以props的形式传递给子组件。一个组件的props和state的变化都会引发该组件及其子组件对应UI的变化,也就是重渲染。

例如上图中,组件2传递给组件4的props变化会引发组件4的重渲染;组件1的state变化则会引发整个组件树的重渲染。

props更像数据管道,state则比较像数据引擎。

现在问题来了,组件4和组件7之间要怎么通信呢。全体起立,让我们再次大声喊出这一句:

在计算机领域,如果有什么事是加一层中间层解决不了的,那就加两层

只需要把组件4和组件7需要通信的数据提升到组件1上作为组件1的state来管理,再通过props层层传递给组件4和组件7就行了。 OK,现在组件树只有三层,通过这样的方式或许还可以接受,但是当组件树有很多层的时候,你岂不是得写很多次这样的props传递的逻辑,这实在是太过辛苦而不优雅的一件事情了。因此,我们也需要引入一个类似全局变量的东西,而react提供的context就是这个全局变量,它允许底层组件直接跨过中间组件,读取顶层组件的数据,像这样:

而引入了全局状态后,就像上一篇文章中讲的那样,由于全局状态比较重要,影响面甚广,因此对它的修改需要比较谨慎,我们就需要引入redux这样的管理者来管理全局状态。你看,整个过程是非常顺其自然的,只有你的react应用足够复杂的时候才需要使用redux,否则就不需要它。

react-redux是怎么解决问题的

结合之前的内容,我们明确:

  1. redux是用来管理全局状态的
  2. react的全局状态被放在顶层组件的context中

那么现在你应该能解答这个这个灵魂之问了:要把redux装进react,总共分几步?

答:三步:

  • 第一步:制定数据管理规则并生成规则执行者,也就是设计reducer和action,生成store;
  • 第二步:将store放在react应用顶层组件的context中;
  • 第三步:react底层组件从context中取出store,对数据进行读写操作

我们延续上一篇文章中管理一个数组的例子:

第一步,我们已经完成了:

import { createStore } from 'redux';

const initState = [];
const reducer = (state = initState, action) => {
    switch(action.type) {
        case 'add':
            return [...state, action.addedItem];
        case 'delete':
            return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
        case 'clear':
            return []
        default:
            return state;
    }
};

const store = createStore(reducer);

第二步,把store放进顶层组件的context中,这个顶层组件就是react-redux中的Provider组件:

import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './App.js';

const initState = [];
const reducer = (state = initState, action) => {
    switch(action.type) {
        case 'add':
            return [...state, action.addedItem];
        case 'delete':
            return [...state.slice(0, action.deletedIndex), ...state.slice(action.deletedIndex + 1)];
        case 'clear':
            return []
        default:
            return state;
    }
};

const store = createStore(reducer);
ReactDOM.render(<Provider store={store}>
                    <App />
                </Provider>,
                document.getElementById('root');

第三步,底层组件从context中取出store对状态进行读写。完成这一步时react-redux又把这个底层组件细分成一父一子两个组件,首先由一个父组件专门负责从context中取出store,把store管理的顶层状态放在自己的数据引擎state中,用store.subcribe监听顶层状态的变化,顶层状态一改变,这个父组件的数据引擎state就跟着改变,然后再把数据通过管道props传递给子组件。脏活累活都被父组件干了,我们开发子组件的时候只需要享用父组件传递过来的props就好了,真是父爱如山啊。另外,对顶层状态进行操作的函数dispatch也需要通过props传递给子组件,这样子组件才可以修改顶层状态嘛。思路已经理通了,react-redux还要做最后一点优化——因为父组件完全没必要直接把store管理的状态整个传给子组件,也没必要把dispatch函数本身传递给子组件。假设顶层组件管理了100多个状态,而实际上你在开发的底层组件可能只想读写其中的一个状态而已——比如这个状态叫theme,那么我希望我写底层组件时,完全不用管其他状态是什么,也不用管要修改其他状态需要dispatch什么action,我只想通过props.theme读状态,通过props.setTheme()写状态。嗨呀其实这不就是加一个中间层就能搞定的事吗,而react-redux需要你写的mapStateToProps函数和mapDispatchToProps函数就是专门用来干这个的。

好了啰里啰嗦一大堆,上面的这一段是告诉你要完成第三步都需要做什么,这其中像从context中取出store这种又脏又累的重复性工作,已经被react-redux在connect这个高阶组件中做完了。所谓高阶组件,其实就是一个函数,传给它一个组件,它返回一个新的组件。在connect这个高阶组件中,你需要传给他mapStateToProps,mapDispatchToProps以及你的业务子组件,它返回给你一个能读写store管理的状态的组件。

talk is cheap, show you the code好伐:

import React from 'react';
import {connect} from 'react-redux';

const mapStateToProps = (state) => {
    return {
        array: state
    }
};

const mapDispatchToProps = (dispatch) => {
    return {
        addItem: (item) => {
            dispatch({
               action: 'add',
               addedItem: item
            });
        }
    }
};

const App = (props) => {
    return (
        <div>
            <div>{props.array}</div>
            <div>
                <button onClick = {props.addItem(1)}>在数组中添加一个1</button>
            <div>
        <div>
        
    )
};

export default connect(mapStateToProps, mapDispatchToProps)(App);

总结

最后,把react-redux的使用方法用下面这个图概括一下:

好了,到现在为止redux的懒人教程系列就算完结了,笔者在写的过程中一直极力避免去详细解析API的具体用法,或者太过深入地解释原理,主要是希望能帮助读者花比较小的代价就能大致理解为什么要用redux/react-redux, 怎么用redux/react-redux。 redux的主要生态是其丰富的中间件,也有实现相似功能的状态管理工具mobx可以学习,在react-hook风头正盛之际,react-redux也提供了对应的hook api,在此就不再一一介绍了,搞懂redux核心用法之后上手这些都会很快的。

水平有限,有哪些写的不清不楚或者表述不正确的地方欢迎多交流指正,觉得有帮助的话求一个赞哦 :)