Redux初学

191 阅读3分钟

平时做项目都是用的项目集成好的react-redux,非常的方便,写了这么久react,redux还真是没用过,昨天学习一下,今天自己写个小demo,记录一下自己的学习成果

Redux简介

平时用React,组件间的数据传递都是通过props传递,如果组件层级比较浅,项目没那么复杂,这样并没有问题;但是如果项目比较复杂,组件很多,如果一个祖组件想传递数据给子孙组件,只能通过props层层传递,这样是很麻烦的,Redux就是来解决这个问题, 解决祖组件向子组件的数据传递问题。
Redux需要一个Store来存储数据,store里的reducer初始化state并定义state的修改规则,组件通过dispatch的action提交对数据的修改,action提交到reducer函数里,根据传入的action的type,返回新的state。

Redux使用

1、创建store,创建reducer,定义state修改规则

import {createStore, combineReducers} from 'redux';
/* 
  1. 需要⼀一个store来存储数据
  2. store⾥的reducer初始化state并定义state修改规则
  3. 通过dispatch⼀一个action来提交对数据的修改
  4. action提交到reducer函数⾥,根据传⼊的action的type,返回新的state
*/
function countReducer (state = 0, action) {
  switch (action.type) {
    case 'ADD':
      return state + 1;
    case 'SUBSTRACT':
      return state - 1;
    default:
      return state;
  }
}

function userReducer (state = 'init value', action) {
  switch (action.type) {
    case 'MYNAME':
      return 'test name';
    default:
      return state;
  }
}

const store = createStore(
  // 多个reduer需要用combineReducers合并
  combineReducers({countReducer, userReducer})
);

export default store;

2、页面通过store.dispatch提交对数据的修改

handleAdd = () => {
    // dispatch方法(分发action)。
    store.dispatch({type: 'ADD'})
  }

  handleSubstract = () => {
    store.dispatch({type: 'SUBSTRACT'})
  }

  handleGetName = () => {
    store.dispatch({type: 'MYNAME'})
  }

3、页面通过store.getState()使用store里的数据

render() {
    // store对象中包括getState方法(获取目前的state)
    const state = store.getState();

    return (
    <div>
        <h3>Redux Page</h3>
        <p>{state.countReducer}</p>
        <p>{state.userReducer}</p>
        <Button type="primary" onClick={this.handleAdd}>ADD</Button>
        <Button type="primary" onClick={this.handleSubstract}>SUBSTRACT</Button>
        <Button type="primary" onClick={this.handleGetName}>MyName</Button>
      </div>
    );
  }

4、页面的state不会自己更新,需要用store.subscribe方法监听state变化(指定监听函数,当state变化时调用)

componentDidMount() {
    // subscribe方法(指定监听函数,当state变化时调用),
    store.subscribe(() => {
      /* 
        默认情况下,当组件的state或props改变时,组件将重新渲染。如果你的render()方法依赖于一些其他的数据,你可以告诉React组件需要通过调用forceUpdate()重新渲染。
        调用forceUpdate()会导致组件跳过shouldComponentUpdate(),直接调用render()。这将触发组件的正常生命周期方法,包括每个子组件的shouldComponentUpdate()方法。
        forceUpdate就是重新render。有些变量不在state上,当时你又想达到这个变量更新的时候,刷新render;或者state里的某个变量层次太深,更新的时候没有自动触发render。这些时候都可以手动调用forceUpdate自动触发render
      */
      this.forceUpdate();
    })
  }

Redux只能做纯状态管理,不能对异步数据进行操作,如果想要其他操作,需要安装相应中间件。

整体流程:
dispatch --> reducer修改state --> subscribe监听state --> 页面重新渲染新的state

手写Redux

redux分析

需要实现的API:createStore: getState, dispatch,subscribe
分析:
最简单的:需要创建一个createStore方法,createStore接收reducers作为参数 稍微复杂: createStore方法可以接收多个reducer,这时候需要combineReducers方法,得到一个组合后的新的reducer

代码实现

1、创建一个createStore方法

export function createStore(reducer) {

  // 获取状态getState
  function getState() {}

  // 更新状态dispatch
  function dispatch() {}

  // 变更订阅subscribe
  function subscribe() {}
  
  return {
    getState,
    dispatch,
    subscribe
  }
}

2、实现三个方法

export function createStore(reducer) {

  // 定义当前state
  let currentState = undefined;
  // 定义监听
  let currentListeners = [];

  // 获取状态getState
  function getState() {
    return currentState;
  }

  // 更新状态dispatch
  function dispatch(action) {
    // 变更state
    currentState = reducer(currentState, action);
    // 更新监听
    currentListeners.forEach(item => item())
    return action;
  }

  // 变更订阅subscribe
  function subscribe(listener) {
    currentListeners.push(listener);
  }

  return {
    getState,
    dispatch,
    subscribe
  }
}

That's all. Thanks

脚踏实地,仰望星空。