初识Redux

70 阅读3分钟

为什么需要redux?

  1. 随着JavaScript开发的应用程序,变得越来越复杂,javaScript需要管理的状态越来越多,越来越复杂。

    • 这些状态包括服务器返回的数据、缓存数据、用户操作产生的数据等等,包括一些UI的状态,比如某些元素是否被选中,是否显示或者隐藏一些元素。
  2. 这些状态变化不断,一个状态的变化可能会引起另一个状态变化。

Redux就是一个帮助我们管理state的容器:Redux是javaScript的状态容器,提供了可预测的状态管理。

Redux核心理念

store(仓库)

把数据(状态state)放到仓库中管理

action(行为)

redux要求通过action来更新数据:

  • 必须通过派发(dispatch)action来修改数据
  • action包括type和content
store.dispatch({type:"change_name",name:"kobe"})

reducer

负责将state和action联系在一起的,他是一个纯函数,返回一个新的state

// reducer就是要返回一个新的state
function reducer(state,action){
    return newState;
}

Redux的三大原则

  1. 单一数据源,整个应用程序的state只存储到一个store,多个store不利于数据的维护
  2. state是只读的,修改state的唯一方法是触发action
  3. 使用纯函数来修改,所有的reducer都应该是纯函数,不能产生副作用。

Redux项目搭建

安装:

// npm的初始化操作
npm init -y
npm install redux
​
// yarn的初始化操作
yarn init -y
yarn add redux

使用过程

  1. 创建一个对象作为要保存的状态

    // 在store.js中定义一个初始化的状态
    const initialState = {
        name: "kobe";
    }
    
  2. 创建store来存储这个state

    // 导入createStore
    const { createStore } = require("redux");
    // 错误写法
    const store = createStore(initialState);
    
    • 但是createStore()函数要求传入一个reducer

1679764476150.png

  1. 声明一个reducer函数,传入createStore函数中

    function reducer(){
        return initialState
    }
    const store = createStore(reducer);
    ​
    // 导出 store
    module.exports = store;
    
  2. 在其他页面来获取state

    // 在index.js中
    const store = require("./store")
    // 通过store.getState 来获取当前的state
    console.log(store.getState());
    // 打印结果
    // { name: 'kobe' }
    
  3. 通过action来修改state

    1. 通过dispatch来派发action
    2. 通常action中都会有type属性,也可以携带其他数据
    // index.js
    const store = require("./store")
    ​
    // 错误的写法
    store.getState().name = "james"
    
    // 不能这么写,只能通过dispatch派发action来修改
    const changeNameAction = {type:"change_name",name:"james"};
    store.dispatch(nameAction);
    ​
    // 再次获取state
    console.log(store.getState());
    // 打印结果
    // { name: "james" }
    
  4. 修改reducer函数中的代码

    /*
      接受两个参数:
      参数1:store中目前保存的state
      参数2:dispatch传递的action(本次需要更新的action)
      返回值:作为store之后存储的state
    */
    function reducer(state,action){
        switch(action.type){
            case "change_name":
                return {...state,name:action.name};
            default:
                return state;
        }
    }
    
  5. 监听store的变化

    // 我们不用在state发生变化后,每次通过store.getState来获取state
    // 通过订阅来监听state的变化
    const unsub = store.subscribe(()=>{
        console.log("订阅数据变化:",store.getState());
    })
    
    // 调用函数取消监听
    unsub();
    

    这样也会有一个小问题,第一次打印的时候state是一个undefined

1679765835116.png

  1. 给reducer函数的入参state一个默认值

    function reducer(state = initialState,action){
        switch(action.type){
            case "change_name":
                return {...state,name:action.name};
            default:
                return state;
        }
    }
    

Redux结构优化

如果我们将所有的逻辑代码写到一起,那么当redux变得复杂时,代码就难以维护。

接下来对代码进行拆分,将store、reducer、action、constants拆分成一个个文件。

store/index.js

const { createStore } = require("redux");
const reducer = require("./reducer");

const store = createStore(reducer);
module.exports = store;

store/reducer.js

const { CHANGE_NAME } = require("./constants");
​
const initialState = {
  name: "kobe",
};
​
function reducer(state = initialState, action) {
  switch (action.type) {
    case CHANGE_NAME:
      return { ...state, name: action.name };
    default:
      return state;
  }
}
​
module.exports = reducer;

store/actionCreator.js

const { CHANGE_NAME } = require("./constants");
​
const changeNameAction = (name) => ({
  type: CHANGE_NAME,
  name,
});module.exports = {
    changeNameAction,
}

store/constants.js

​
const CHANGE_NAME = "change_name";module.exports = {
    CHANGE_NAME
}

以上我们做的优化有这么几点:

  • 将派发的action生成过程放到一个actionCreator函数中
  • 又将actionCreator函数放到一个独立的文件中,以后所有创建action都放在这里
  • 将reducer函数和actionCreator函数都用到的字符串,声明常量放到一个单独的constants文件中
  • 将reducer和默认初始状态放到一个独立的文件中。

1679766455616.png

Redux使用流程

1679767467182.png

以上全部,谢谢!