Redux基础篇

前言

为何有使用

随着JavaScript单页应用开发日趋复杂,管理不断变化的state变得十分困难html

三大原则

  • 【一】单一数据流
    • 整个应用的 state被储存在一棵object tree中,而且这个object tree只存在于惟一的store
  • 【二】只读state
    • 惟一改变state的方法就是触发action
  • 【三】使用reducer函数执行修改
    • 根据触发的action来通知reducer函数来执行相应修改state动做

设计思想

  • 【一】将整个应用状态存储到到一个地方,称为store,里面保存一棵状态树state tree
  • 【二】组件能够派发dispatch行为actionstore,而不是直接通知其它组件
  • 【三】其它组件能够经过订阅store中的state来刷新本身的视图

基础使用

本文以一个小计数器为例子逐一讲解redux

原生版

  • 【0】页面结构设计
<body>
    <div id="counter">
        <div id="counter-value"></div>
        <button id="increment-btn">+</button>
        <button id="decrement-btn">-</button>
    </div>
</body>
复制代码
  • 【1】定义action动做
const INCREMENT = Symbol.for('INCREMENT');
const DECREMENT = Symbol.for('DECREMENT');
复制代码
  • 【2】建立reducer函数,用来管理状态
function reducer(state, action) {
  switch (action.type) {
    case INCREMENT:
      return state + 1; // 返回一个加1的新状态
    case DECREMENT:
      return state - 1;// 返回一个减1的新状态
    default:
      return state;
  }
}
复制代码
  • 【3】建立仓库store
import {createStore} from 'redux';
let store = createStore(reducer,initState);
复制代码
  • 【4】挂载状态&&订阅状态
let counterValue = document.getElementById('counter-value');
let incrementBtn = document.getElementById('increment-btn');
let decrementBtn = document.getElementById('decrement-btn');
function render() {
  counterValue.innerHTML = store.getState();
}
render();
let unsubscribe = store.subscribe(render);
复制代码
  • 【5】派发动做
incrementBtn.addEventListener('click',function () {
  store.dispatch({
    type:INCREMENT
  })
})
decrementBtn.addEventListener('click',function () {
  store.dispatch({
    type:DECREMENT
  })
})
复制代码
  • 【6】卸载状态(取消订阅状态)
setTimeout(()=>{
  unsubscribe()
},3000)
复制代码

React

  • 【1】定义action动做
const INCREMENT = Symbol.for('INCREMENT');
const DECREMENT = Symbol.for('DECREMENT');
复制代码
  • 【2】建立reducer函数,用来管理状态
function reducer(state, action) {
  switch (action.type) {
    case INCREMENT:
      return state + 1; // 返回一个加1的新状态
    case DECREMENT:
      return state - 1;// 返回一个减1的新状态
    default:
      return state;
  }
}
- 【3】建立仓库`store`
```JS import {createStore} from 'redux'; let store = createStore(reducer,initState); 复制代码
  • 【4】绑定action指派对象
const boundActions = bindActionCreators(actions,store.dispatch)
复制代码
  • 【5】建立组件
export default class Counter extends Component {
  state = {number:store.getState()}
  componentDidMount(){
    this.unsubscribe=store.subscribe(()=>{
      this.setState({
        number:store.getState()
      })
    })
  }
  componentWillUnmount(){
    this.unsubscribe()
  }
  render() {
    return (
      <> <p>{this.state.number}</p> <button onClick={boundActions.increment}>+</button> <button onClick={boundActions.decrement}>-</button> </> ) } } 复制代码

原理进阶

createStore

  • 参数:reducer,初始状态preloadedState
  • 返回:
    • getState
    • subscribe
    • dispatch
  • 源码实现
function createStore(reducer,preloadedState){
      let currentReducer = reducer;
      let currentState = preloadedState;
      let currentListeners = [];
      function getState(){
          return currentState;
      }
      function dispatch(action){
          if(!isPlainObject(action)){
              throw new Error('action必须是一个纯对象');
          }
          if(typeof action.type === 'undefined'){
              throw new Error('action必须有type属性')
          }
          currentState = currentReducer(currentState,action);
          for(let i = 0;i<currentListeners.length;i++){
              const listener = currentListeners[i];
              currentListener();
          }
          return action;
      }
      function subscribe(listener){
          currentListeners.push(listener);
          return function(){
              const index = currentListeners.indexOf(listener);
              currentListeners.splice(index,1);
          }
      }
      return {
          getState,
          dispatch,
          subscribe
      }
  }
复制代码

bindActionCreators

  • 参数:actionCreatorsdispatch
  • 返回:包装后的对象函数
  • 源码实现
function bindActionCreators(actionCreators,dispatch){
      if(typeof actionCreators === 'function'){
          return bindActionCreator(actionCreators,dispatch);
      }
      const boundActionCreators = {};
      for(let key in actionCreators){
          if(actionCreators.hasOwnProperty(key)){
              boundActionCreators[key] = bindActionCreator(actionCreators[key],dispatch);
          }
      }
      return boundActionCreators;
  }
  fucntion bindActionCreator(actionCreator,dispatch){
      return function(){
         return dispatch(actionCreator.apply(this,arguments));
      }
  }
复制代码

combineReducers

  • 参数:reducers对象
  • 返回:reducers函数
  • 源码实现
function combineReducers(reducers){
      const reducerKeys = Object.keys(reducers);
      return function(state={},action){
          const nextState = {};
          for(let i = 0;i<reducerKeys.length;i++){
              const reducer = reducers[key];
              const previousStateForkey = state[key];
              const nextStateForkey = reducer(previousStateForkey,action);
              nextState[key] = nextStateForkey;
          }
          return nextState;
      }
  }
复制代码
相关文章
相关标签/搜索