Redux学习之初学Redux

162 阅读4分钟

一、Redux简介

1、作用

管理state

2、理念

为了让state的变化做到可追溯,不管是redux还是redux toolkit都是要求每个更改state的操作都要通过派发(despatch) action来实现。

  • action是一个JS对象

    const addAction = {
        type: "ADD_SALARY",
        num: 2000
    }
    const subAction = {type: "SUB_SALARY", num: 2000}
    
  • 那么一个action怎么能操作state的呢?——reducer(必须是纯函数,不能有副作用)

    const initialState = {
        salary: 10000,
    }
    
    function reducer(state = initialState, action) {
        switch (action.type) {
            case "ADD_SALARY":
                // 为了避免副作用产生,需要重新创建一个对象,放入state属性,同时后面的属性将覆盖前面的属性
                return {...state, salary: state.salary + action.num}
            case "SUB_SALARY"::
                return {...state, salary: state.salary - action.num}
            default:
                return state;
        }
    }
    
    • 随着应用变大,你可以reducer它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。
function visibilityFilter(state = 'SHOW_ALL', action) {
  switch (action.type) {
    case 'SET_VISIBILITY_FILTER':
      return action.filter
    default:
      return state
  }
}

function todos(state = [], action) {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
    case 'COMPLETE_TODO':
      return state.map((todo, index) => {
        if (index === action.index) {
          return Object.assign({}, todo, {
            completed: true
          })
        }
        return todo
      })
    default:
      return state
  }
}

import { combineReducers, createStore } from 'redux'
let reducer = combineReducers({ visibilityFilter, todos })
let store = createStore(reducer)
  • reducer怎么知道何时执行了哪个action呢?——despatch方法,是redux通过createStore()所创建的store对象中的方法。
import { createStore } from 'redux';

const store = createStore(reducer)

// 在派发之前监听store的变化
store.subscribe(() => {
  console.log(store.getState())
})
// 派发actions
store.dispatch(ADD_SALARY);
store.dispatch(SUB_SALARY);

3、三大原则

单一数据源

整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中:

  • Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护;
  • 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;

State是只读的

唯一改变 state 的方法就是触发 action,action 是一个用于描述已发生事件的普通对象。

  • 这样就确保了View或网络请求都不能直接修改state,相反它们只能表达想要修改的意图,它们只能通过action来描述自己想要如何修改state;
  • 这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
  • Action 就是普通对象而已,因此它们可以被日志打印、序列化、储存、后期调试或测试时回放出来。

使用纯函数来执行修改

通过reducer将 stateactions联系在一起,并且返回一个新的State:

  • 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;
  • 但是所有的reducer都应该是纯函数,不能产生任何的副作用;
  • 随着应用变大,你可以把它拆成多个小的 reducers,分别独立地操作 state tree 的不同部分,因为 reducer 只是函数,你可以控制它们被调用的顺序,传入附加数据,甚至编写可复用的 reducer 来处理一些通用任务,如分页器。

经过上面的介绍不难写出一个基本的redux使用逻辑代码

import { createStore } from 'redux';

const ADD_SALARY = "ADD_SALARY";
const ADD_NUMBER = "SUB_SALARY";

// 1.创建一个对象,作为状态
const initialState = {
    salary: 0,
}

// 2. 创建reducer
// 当第一次调用reducer时,state为undefined则使用默认值initialState
const reducer = (state = initialState, action) => {
    // 6.修改reducer中的代码
    switch (action.type) {
        case ADD_SALARY:
            return {...state, salary: state.num + action.num};
        case SUB_NUMBER:
            return {...state, salary: state.num - action.num}
        default:
            return state;
    }
}

// 3.创建store并传入reducer
const store = createStore(reducer)

// 7.在派发之前监听store的变化
store.subscribe(() => {
    console.log(store.getState())
})

// 4.创建actions
const addAction = {type: ADD_SALARY, num: 2000}
const subAction = {type: SUB_SALARY, num: 2000}

// 5.分发actions
store.dispatch(addAction);
store.dispatch(subAction);

二、redux的基本使用

1、安装redux

yarn add redux

2、redux模块化

创建一个项目

yarn init

安装redux

yarn add redux

创建src目录,创建index.js

修改packge.json可以执行index.js,执行yarn start时相当于执行node src/index.js

"scripts": {
  "start": "node src/index.js"
}

为了开发时代码更加规范,我们将store、reducer、action、constants拆开,而不是写在一起

image-20221118144053306.png

创建store/index.js文件:

import redux from 'redux'
import reducer from './reducer.js'

const store = redux.createStore(reducer);

export default store;

创建store/reducer.js文件:

import {
    ADD_NUMBER,
    SUB_NUMBER
} from './constants.js'

const initialState = {
    counter: 0,
}

function reducer(state = initialState, action) {
    switch (action.type) {
        case ADD_NUMBER:
            return {...state, counter: state.counter + action.num}
        case SUB_NUMBER:
            return {...state, counter: state.counter - action.num}
        default:
            return state;
    }
}

export default reducer;

创建store/actionCreators.js文件:

import {
    ADD_NUMBER,
    SUB_NUMBER
} from './constants.js'

const addAction = num => ({
    type: ADD_NUMBER,
    num
})

const subAction = num => ({
    type: SUB_NUMBER,
    num
})

export { addAction, subAction }

创建store/constants.js

export const ADD_NUMBER = "ADD_NUMBER";
export const SUB_NUMBER = "SUB_NUMBER";

在项目的index.js中进行测试

import store from './store/index.js'
import { addAction, subAction} from './store/actionCreators.js'

store.subscribe(() => {
    console.log(store.getState())
})

store.dispatch(addAction(10))
store.dispatch(subAction(5))