Redux的基本使用

277 阅读5分钟

总结一下Redux。

什么是Redux?

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。说人话就是对应大型项目中数据使用情况比较复杂的时候,用来做数据的分享和使用的。他将所有数据也就是所说的状态存储在一个对象上,从而方便我们统一管理。

Redux三大原则:

  1. 单一数据源: 整个项目用Redux管理的数据,应该都由一个store对象来进行存储
  2. 只读状态:
    对store对象进行修改的方法,只有通过dispath一个action来改变。对应对象中的方法,就是只有getter方法,没有setter方法。
  3. 使用纯函数去修改

对于纯函数,我的理解就是对函数进行相同的输入,则应当得到相同的输出以以下方法作为例子:

fn1(1) // 1
fn1(2) // 2
fn1(1) // 此时再次进行求值,如果是1,则是纯函数,如果不是,那么就不是纯函数

因此在修改的值中,最好不能输出带有array.push之类的方法,这样会改变返回值的值却不改变地址值,导致Redux无法修改

Redux的工作原理

首先介绍以下Redux的三剑客:action,store,reducer 。如果把Redux当做一个饭店的,这三剑客对应都有自己的工作:

  • action:主要负责定义和创建各种action事件对象,从而方便store通过dispatch去调用reducer,可以把它当整个Redux的服务员
  • store:主要负责直接跟组件对话,通过指导组件传达的各种需求使用对应的action方法,然后通知reducer去进行相应的操作。可以当做整个Redux的老板
  • reducer:主要负责将store传给它的数据进行加工,然后将得到的新的数据回调给store,可以把它当做Redux的厨师 redux原理图.png 这是网上找的Redux的工作图。可以看到,三剑客通过各自的职能,让数据在Redux和React组件中互相传递了起来。

Redux的代码(不包括react-redux的部分)

接下里不用react-redux的情况下,展示redux的方面的使用代码。此时我们要使用redux进行一个react组件的数据存储。比如我要给ShowTags组件展示一堆从redux中拿到的数据,用button控制是否显示

redux目录

首先需要yarn add redux引入redux库,然后在src目录下创建一个新的目录

  • src
      • redux
        • action
          • showTagsAction.js
        • reducer
          • showTagsReducer.js
        • store.js
          接下来就是对各文件内部进行书写
-showTagsAction.js
//这个文件定义对store进行dispath的各种方法
const showTagsAction = (isShow)=>{
    return {type:"showTags",data:isShow}
}

export default showTagsAction 

-showTagsReducer.js
//这个文件中主要写要怎么将store传来的数据进行加工
export default function showTagsReducer(preState=false,action){
    const {type,data} = action
    switch (type){
        case "showTags":
            return data
        default:
            return preState;
    }
}

-store.js
//引入createStore,createStore是最核心的api,用于创建一个redux
import {createStore} from "redux"
//引入在reducer中写好的相关reducer代码
import showTagsReducer from "./reducer/showTagsReducer";
//导出写好的store文件
export default createStore(showTagsReducer)

接着就可以在showTags组件中写代码了

这是showTags组件内写的代码
import React, {Component} from 'react';
import store from "../../redux/store"
import showTagsAction from "../../redux/action/showTagsAction";

export default class index extends Component {
    state = {tagsArr:[{id:"001",name:"大毛"},{id:"002",name:"小毛"}],isShow:true}
    
    //在组件挂载的时候绑定一个store方法中的subscribe方法,方便随时查看store内的值时候变化
    componentDidMount() {
        store.subscribe(()=>{
            this.setState(()=>{
                return {...this.state,isShow:!this.state.isShow}
            })
        })
    }
    //当change state按钮被点击后,触发该函数,使得store发送一个dispath命令给reducer
    changeState = ()=>{
        const {isShow} = this.state
        store.dispatch(showTagsAction(isShow))
    }
   
    render() {
        const {tagsArr} = this.state
        return (
            <>
                <ul>
                    {store.getState() ? tagsArr.map(item=><li key={item.id}>{item.name}</li>) : "空"}
                    <button onClick={this.changeState}>change state</button>
                </ul>
            </>
        )
    }
}
  • 在这个方法中,总共用到了store方法的如下方法:
    • getState:获取store中存储的数据,并且展示
    • subscribe:订阅一个store对象,使得当组件挂载时候监听到react对象的变化
    • dispath:使得store对象派遣一个action指令给reducer进行操作

redux thunk:

redux往往用于数据的异步操作,此时我们需要用redux-thunk组件来实现代码。比如我们需要一个按钮在点击+1的时候间隔一分钟,再渲染页面上的值,代码如下:

const addNum = (num)=>{
    return {type:"addNum",state:num}
}

const addNumAsync = (num)=>{
    return (dispatch) => {
        setTimeout(() => {
            dispatch(addNum(num));
        }, 1000);
    };
}
export default addNumAsync;

此时如果用redux管理,按照原先的操作,就会报如下错误:

image.png

这里之所以会报错,是因为redux只能接受一个简单对象,对异步这类对象处理无能为力。所以,我们需要引入中间件来进行中间可能进行的所有操作。这里我们用redux的原生api----applyMiddleware,这个api需要传入一个中间件数组,然后来依次执行中间件中的函数。我们需要借助一个库把需要进行异步操作的action给包装一下,让他成为一个增强版的action,能让dispath调用。查阅得知我们可以用redux-thunk,于是导入,最终代码形成如下:

import {applyMiddleware, createStore} from "redux";
import thunk from 'redux-thunk';
import appReducer from "./reducer/app_reducer";


export default createStore(appReducer,applyMiddleware(thunk))

此时代码就可以跑通了,得到了一个异步的使用方法。

以上这就是redux的基本使用方法,可以看到此时用的redux效率很低,即当我数据量增加时,相应的代码量也会提升,且监听的数目也会增加,不方便书写,于是react官方出了一个react-redux库解决这个问题。