Redux

66 阅读2分钟

1. redux 三大原则

  • 单一数据源
    • 整个应用程序的 state 被存储在一颗 object tree 中,并且这个 object tree 只存储在一个 store 中;
    • 可以创建多个 store, 但是这样做不利于数据的维护;
    • 单一的数据源可以让整个应用程序的 state 变得方便维护、追踪、修改
  • State是只读的
    • 唯一修改 State 的方法一定是触发 action,不要试图在其他地方通过任何的方式来修改 State;
    • 可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心竞态的问题;
  • 使用纯函数来执行修改
    • 通过 reducer 将旧 state 和actions 联系在一起,并且返回一个新的 State;
    • 随着应用程序的复杂度增加,我们可以将 reducer 拆分成多个小的 reducers,分别操作 state tree 的一部分;
    • 所有的 reducer 都应该是纯函数,不应该产生任何的副作用;

2. redux 的使用

  • npm install redux
  • 代码
// src/index.js
/**
 * redux代码优化:
 *   1. 将派发的action生成过程放到一个actionCreators函数中
 *   2. 将定义的所有的actionCreators的函数,放到一个独立的文件中: actionCreators.js
 *   3. actionCreators和reducer函数中使用字符串常量是一致的,所以将常量抽取到一个独立的constants的文件中
 *   4. 将reducer和默认值(initalState)放到一个独立的reducer.js文件中,而不是在index.js
 */

const store = require("./store")
const { changeNameAction, addCounterAction } = require("./store/actionCreators")

const unSubcribe = store.subscribe(() => {
  console.log("订阅数据的变化", store.getState())
})

// actionCreators: 帮助我们创建action
// const changeNameAction = name => ({ type: "change_name", name })
// const addCounterAction = num => ({ type: "add_counter", num })
// 修改store中的数据: 必须action
store.dispatch(changeNameAction("Kobe"))
store.dispatch(changeNameAction("lilei"))

store.dispatch(addCounterAction(10))
store.dispatch(addCounterAction(20))
store.dispatch(addCounterAction(30))
store.dispatch(addCounterAction(100))

// src/store/index.js
const { createStore } = require("redux")
const { reducer } = require("./reducer")
// 创建的 store
const store = createStore(reducer)
module.exports = store


// src/store/reducer.js
const { CHANGE_NAME, ADD_COUNTER } = require("./constants")

// 初始化的数据
const initialState = {
  name: "lwz",
  counter: 100
}

// 定义reducer函数: 纯函数
// 两个参数:
// 参数一: store 中目前保存的 state
// 参数二: 本次需要更新的action(dispatch传入的action)
// 返回值: 它的返回值回座位store之后存储的state
function reducer(state = initialState, action) {
  switch (action.type) {
    case CHANGE_NAME:
      return { ...state, name: action.name }
    case ADD_COUNTER:
      return { ...state, counter: state.counter + action.num }
    default:
      return state
  }
}

module.exports = { reducer }


// store/constants.js
const CHANGE_NAME = "change_name"
const ADD_COUNTER = "add_counter"

module.exports = { CHANGE_NAME, ADD_COUNTER }


// store/actionCreators.js
const { CHANGE_NAME, ADD_COUNTER } = require("./constants")

const changeNameAction = name => ({ type: CHANGE_NAME, name })
const addCounterAction = num => ({ type: ADD_COUNTER, num })

module.exports = {
  changeNameAction,
  addCounterAction
}