手写react-redux

136 阅读2分钟

学习目标:

  • 实现connect高阶组件
  • 实现Provider

资源:

首先通过react-redux API去实现一个组件

  • 项目入口文件
import React from 'react';
import ReactDOM from 'react-dom/client';
// import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
import store from './store'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
  • 创建一个使用connect的组件
import React from 'react'
import { connect } from 'react-redux'

class ReactReduxPage extends React.Component {

    add = () => {
        this.props.dispatch({ type: 'ADD' })
    }
    render() {
        return (
            <div>
                { console.log(this.props,'props')}
                <button onClick={this.add}>dispatch: add</button>
                <p>{this.props.count}</p>
            </div>
        )
    }

}

const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        dispatch
    }
}

const mapStateToProps = (state, ownProps) => {
    return state
}


export default connect(mapStateToProps,mapDispatchToProps)(ReactReduxPage)

首先我们去实现一个Provider组件

  • 思考: 通过上述入口文件的代码可以了解到,provider接收store和后代组件
  • 那么,当我们想让后代子孙组件可以使用当前的store,就会行程跨组件通信,而实现跨组件通信的方法context全局对象方法
  • 所以引出我们需要创建一个context对象,然后通过context.Provider的value参数把store传递给后代子孙组件

再去实现一个connect的高阶函数

  • 思考: 高阶组件connect接收mapStateToProps,mapDispatchToProps,还有当前的组件和组件自带的一些参数
  • 高阶函数会返回一个新的组件
  • mapStateToProps是通过调用这个函数把更新后的state返回给这个函数
  • 那么我更新后的state去哪里获取呢?? store的getState方法
  • 那store就可以通过全局对象Context去获取
  • mapDispatchToProps是通过这个函数把dispatch返回给这个函数
  • 那么我的dispatch去哪里获取呢?? store的dispatch方法
  • 那store就可以通过全局对象Context去获取
import react from 'react'
// 获取全局对象

const Context = react.createContext()

export default function Provider({ store, children }){
    return <Context.Provider value={store}>{children}</Context.Provider>
}


const connect = (mapStateToProps,mapDispatchToProps) => WrapperComponent => props => {
    // 1. 先获取store
    // 后代消费子孙组件的store可以通过三种方法
        // 1. contextType 只能用在类组件中,并且只能订阅一个
        // 2. useContext  自定义hook使用
        // 3. consumer    都可以用
    const store = useContext(Context)
    const { getState, dispatch, subscribe } = store
    
    // 组件中需要使用mapStateToProps,mapDispatchToProps,所以返回这两个函数的值
    // 调用mapStateToProps方法, 返回更新后的所有state
    let stateProps = mapStateToProps(getState())
    // 添加默认值
    let dispatchProps = { dispatch }
    // 有的时候传递给我们的mapDispatchToProps是个函数,所以需要我们去判断下当前是否为函数
    if(typeof mapDispatchToProps === 'function') {
    // 如果是函数就直接调用函数方法并且把dispatch直接传递过去
        dispatchProps = mapDispatchToProps(dispatch)
    } else if(typeof mapDispatchToProps === 'object') {
    // 如果是对象就需要使用redux中的bindActionCreators来帮助我们在内容实现dispatch({type: 'ADD'}) 调用
        dispatchProps = bindActionCreators(mapDispatchToProps, dispatch)
    }
    
    
    return <WrapperComponent {...props} {...stateProps} {...dispatchProps}/>
    
}

这样我们就实现一个简单的react-redux中的Provider和connect