Skip to content

redux原理 #93

@et-hh

Description

@et-hh

redux

redux常用接口有:createStore/subscribe/dispatch/getState
redux基本用法如下:

import {createStore} from 'redux';

//给初始状态一个默认值:{count: 0}
function reducer(state = {count: 0}, action) {
    switch (action.type) {
        case '+':
            return {...state, {money: state.count + 1}};
        case '-':
            return {...state, ...{money: state.count - 1}};
        default:
            return state;
    }
}

const store = createStore(reducer);

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

store.dispatch({ type: 'add' })

核心在于createStore的实现,简单原理如下:

function createStore(reducer, initialState) {
    // 存一个内部状态
    let currentState = initialState

   const listeners = []

   // dispatch
   function dispatch(action) {
       currentState = reducer(currentState, action)
       listeners.forEach(it => it())
   }

   function subscribe(fn) {
      listeners.push(fn)
   }
    
    return {
        dispatch,
        subscribe,
        getState() { return currentState  }
    }
}

react-redux

从上面可以看出redux本身并无法触发更新,于是针对react开发了个react-redux用于触发更新
react-redux在组件中基本使用如下:

class xxxComponent extends React.Component{
    constructor(props){
        super(props)
    }
    componentDidMount(){
        this.props.actionA();
    }
    render (
        <div>
            {this.props.propA}
        </div>
    )
}

export default connect(
    state=>{
        return {
            propA: state.propA,
            // ...
        }
    },
    dispatch=>{
        return {
            actionA(dispatch) { dispatch({ type: 'add' }) },
            // ...
        }
    }
)(xxxComponent)

其核心在connect,这是个高阶函数,简单实现如下:

function connect(mapStateToProps, mapActionsToProps) {
    return function wrapWithConnect() {
       export class Connect extends Component {
          constructor(props, context) {
              // 这里从context拿的store,这个怎么来的看下面provider部分
              this.store = props.store || context.store
              this.state = {
                  storeState: this.store.getState()
              }
              ...
          }
          render() {
              // 渲染被包裹的组件,并把传入的状态和action作为props传入
              this.renderedElement = createElement(
                   WrappedComponent,
                   this.mergedProps //mearge stateProps, dispatchProps, props
              )
              return this.renderedElement;
          },
          handleChange() {
              const newState = this.store.getState()
              if (hasChanged(newState, this.state.storeState)) {
                   this.setState({ storeState: newState }) // 关键是这句,一旦store发生变化了,会通过setState设置这个内部组件的状态,而setState可以让组件和其子组件重新渲染
              }
          },
          subscribe() {
              this.unsubscribe = this.store.subscribe(this.handleChange.bind(this))
          },
          componentDidMount() {
              this.subscribe()
          },
          componentWillUnmount() {
              this.unsubscribe()
          }
      }
    }
}

并提供一个Provider组件用于全局提供状态,简单实现如下(抄自阮一峰文章):

class Provider extends Component {
  getChildContext() {
    return {
      store: this.props.store
    };
  }
  render() {
    return this.props.children;
  }
}

可以看到其原理是利用了reactcontext特性

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions