Redux技术原理

1. 什么是Redux

Redux是一个通过叫做action的事件,管理和更新应用程序状态的js库或者说是一种模式。使用Redux
可以使我们更容易地理解应用程序中的状态或者说数据何时,何地,为什么被更新,以及这种更新所
带来的行为。

2. 使用Redux的场景

  • 应用程序中具有大量的数据状态分布在程序的多个地方
  • 数据状态被频繁的更新
  • 更新逻辑非常复杂
  • 具有大规模的代码被多人同时开发和维护

3. Redux相关的工具和库

  • React-Redux:提供React组件与Redux store进行交互的方式。
  • Redux Toolkit: 提供编写Redux逻辑的模式和工具库,简化开发任务,Redux开发最佳实践。
  • Redux DevTools Extension: 提供调试Redux的方法。

4. Redux Store

每一个Redux应用的中心是store, 它保存了应用的所有数据状态。store的本质是一个javascript对象,
具有一些特殊的方法和能力使得它与众不同。

  • 不能直接修改保存在store中的数据状态
  • 唯一引起store中的state变化的是action对象,它描述了要发生什么行为,创建action对象然后
    将它分发给store, 告诉它发生的事件。
  • 当一个action被分发后,store会调用reducer函数,让它基于action以及旧的state,计算出新的state。
  • 最后store会通知订阅者状态已经更新,最后UI会根据最新的数据重新渲染。
const initialState = {
  value: 0
};

const reducers  =  {
  'counter/increment': (state, payload) => {
    return {
      ...state,
      value: state.value + 1
    };
  },
  'counter/decrement': (state, payload) => {
    return {
      ...state,
      value: state.value - 1
    };
  }
};

const reducers = (state=initialState, action) => {
  const { type, payload, rest } = action;
  const reducer = reducers[type];
  return reducer ? reducer(state, payload, rest) : state;
};

// 根据reducer创建store
const store = Redux.createStore(reducers);

// 处理用户点击事件,分发action对象
document.getElementById('increment').addEventListener('click', function () {
  store.dispatch({ type: 'counter/incremented' })
}) 
document.getElementById('decrement').addEventListener('click', function () {
  store.dispatch({ type: 'counter/decremented' })
})

// 当store中数据更新时调用订阅函数执行UI更新逻辑
store.subscribe(() => {
  const state = store.getState();
  const valueElment = document.getElemmentById('value');
  valueElment.innerHTML = state.value.toString();
});

5. Redux 术语

  • Actions
    一个action就是一个具有type属性的普通javascript对象,你可以将它看作描述发生在应用程序中的
    事件。type属性应当是一个描述性的名称,'domain/eventName', 第一部分表明action属于哪个功能
    模块,第二部分指定一个发生事件名称。除了type属性,Actioin也可以包含其他字段,作为惯例可以
    将其他信息存储在payload属性当中。
const addTodoAction = {
  type: 'todos/todoAdded',
  payload: 'Buy milk'
}
  • Reducers
    一个reducer就是一个函数接受当前的state和action, 然后决定是否有必要更新state,然后返回新的
    state。你可以将它看作一个事件监听器,根据接收到的action (event) type,进行事件处理。
    reducer 应该遵循下列规则:
  1. 应该根据当前state 和 action,计算新的state。
  2. 不允许修改当前state,应该复制当前的state,然后修改副本。
  3. 不应当进行异步操作或者产生随机数等有副作用的逻辑。

reducer 工作逻辑:

const initialState = { value: 0 }
function counterReducer(state = initialState, action) {
  // Check to see if the reducer cares about this action
  if (action.type === 'counter/incremented') {
    // If so, make a copy of `state`
    return {
      ...state,
      // and update the copy with the new value
      value: state.value + 1
    }
  }
  // otherwise return the existing state unchanged
  return state
}
  • Store
    当前应用程序的state,保存在一个叫Store的object中,它根据传入的reducer创建并具有
    返回当前state的接口getState。
import { createStore } from 'redux'
const store = createStore(reducers);
console.log(store.getState())
  • Dispatch
    修改Store的唯一方式就是调用store.dispatch(action) 方法, store然后会调用reducer,保存新产生
    的state数据。你可以将发送action理解为触发一个事件。
store.dispatch({ type: 'counter/incremented' })
console.log(store.getState())  // {value: 1}
  • Selectors
    Selectors 就是从store中选取指定state的函数,它避免了应用程序不同部分读取store中相同state的
    代码逻辑重复。
const selectCounterValue = state => state.value

const currentValue = selectCounterValue(store.getState())
console.log(currentValue) // 2

6. Redux的数据流及原则

数据流:

  • state 描述应用程序在特定时间点的状态
  • UI 基于此state进行渲染
  • 发生用户事件时,基于action 的type对state进行更新
  • UI基于最新的state重新渲染
    原则:
  • 单一数据源
  • 只读state
  • 通过reducer纯函数进行state更新

7. Redux应用工作流程

  • 初始设置
    1. 使用root reducer创建store
    2. store调用一次reducer产生初始state并保存
    3. UI第一次渲染时获取初始化的state,并使用这些数据决定渲染哪些部分,UI同时订阅了store的更新,
      因此UI能感知到store中state的变化。
  • 更新
    1. 应用中发生交互事件(点击事件)
    2. 应用派发一个action到Redux的store (dispatch({type: 'counter/incremented'}))
    3. store使用当前的state和action执行reducer函数,产生新的state并保存。
    4. store通知所有的订阅store更新的UI组件
    5. UI组件检测自己使用的那部分state数据是否发生更新
    6. UI组件使用新数据强制重新渲染

8. Redux store 内部实现

  • Store内部保存有应用当前的状态值以及reducer函数
  • getState方法返回当前应用状态
  • subscribe方法将监听器回调函数存入数组,并返回unsubscribe 函数取消监听
  • dispatch方法调用reducer 函数,并保存新生成的state值,并执行监听函数
  • store自己发送一个action,并调用reducer初始化state
  • store是一个具有dispatch, subscribe, getState接口方法的对象
function createStore(reducer, preloadedState) {
  let state = preloadedState
  const listeners = []

  function getState() {
    return state
  }

  function subscribe(listener) {
    listeners.push(listener)
    return function unsubscribe() {
      const index = listeners.indexOf(listener)
      listeners.splice(index, 1)
    }
  }

  function dispatch(action) {
    state = reducer(state, action)
    listeners.forEach(listener => listener())
  }

  dispatch({ type: '@@redux/INIT' })

  return { dispatch, subscribe, getState }
}

posted @ 2023-02-24 20:31  箫笛  阅读(96)  评论(0)    收藏  举报