手写一个react-redux,原理一目了然

时间:2021-1-8 作者:admin

react-redux的功能如下:

  1. Provider 为后代组件提供store
  2. connect 为组件提供数据和变更方法
  3. 数据变化时自动更新组件

了解react-redux的功能移步这里

下面我们开始实现react-redux的几个功能:

//my-react-redux.js
import React, {useContext, useReducer, useLayoutEffect} from "react";
const Context = React.createContext(); //创建全局state

//1. 实现Provider组件:为后代组件提供store
export function Provider({store, children}) {
  return <Context.Provider value={store}>{children}</Context.Provider>;
}

//2. 实现connect方法:为组件提供数据和变更方法
export const connect = (
mapStateToProps = state => state,     //默认是一个方法
mapDispatchToProps
) => WrappendComponent => props => {  // WrappendComponent 是受益的组件
  const store = useContext(Context)
  const {dispatch, getState, subscribe} = store
  const stateProps = mapStateToProps(getState()) //获取需要的state
  let dispatchProps = { dispatch }
  // 让函数强制更新的方法
  const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
  //mapDispatchToProps可以是function与object
  if (typeof mapDispatchToProps === "function") {
     dispatchProps = mapDispatchToProps(dispatch)
  } else if (typeof mapDispatchToProps === "object") {
     dispatchProps = bindActionCreators(mapDispatchToProps, dispatch)
  }
  //3. 实现同步副作用 state改变时自动更新组件
  useLayoutEffect(() => {
    //订阅state改变
    const unsubscribe = subscribe(() => {
       forceUpdate() //强制刷新
    })
    //返回一个 注销订阅函数
    return () => {
     if (unsubscribe) {
       unsubscribe()
     }
    }
  }, [store])
  //将state与dispatch映射到组件内 完成connect方法的任务
  return <WrappendComponent {...props} {...stateProps} {...dispatchProps} />
}

function bindActionCreator(creator, dispatch) {
  return (...args) => dispatch(creator(...args))
}
//@connect()装饰器内需要一个bindActionCreators方法
//作用是结构creators,只需写type即可自动实现dispatch方法,让creators写的更简单
function bindActionCreators(creators, dispatch) {
  const obj = {};
  for (let key in creators) {
    obj[key] = bindActionCreator(creators[key], dispatch)
  }
  return obj
}

了解@connect()装饰器移步这里

实现hooks API:

  1. useSelector 获取store state
  2. useDispatch 获取dispatch
export function useSelector(selector) {
  const store = useStore()
  const {getState, subscribe} = store
  const selectedState = selector(getState())
  const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
  useLayoutEffect(() => {
    const unsubscribe = subscribe(() => {
     forceUpdate()
    });
    return () => {
     if (unsubscribe) {
       unsubscribe()
     }
   };
  }, [store])
  return selectedState
}
export function useDispatch() {
  const store = useStore()
  return store.dispatch
}
export function useStore() {
  const store = useContext(Context)
  return store
}

使用:

import React, {useCallback} from "react"
import {useSelector, useDispatch} from "react-redux"
export default function ReactReduxHookPage({value}) {
  const dispatch = useDispatch()
  const add = useCallback(() => {
    dispatch({type: "ADD"})
  }, [])
  const count = useSelector(({count}) => count);
  return (
    <div>
      <h3>{count}</h3>
      <button onClick={add}>add</button>
   </div>
  )
}
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。