zoukankan      html  css  js  c++  java
  • 实现一个react-redux

    react-redux是配合react库管理数据的一种方式,下面试redux的简单实现。

    参考http://huziketang.mangojuice.top/books/react/lesson30

    import React, {Component} from 'react'
    import ReactDOM from 'react-dom'
    import PropTypes from 'prop-types'
    import './index.css'
    
    
    /**
     * connect函数是高阶组件,用于包装纯组件并返回一个组件。使store中的数据可以传入到被包装组件,和响应store中数据的更新
     * connect接收两个方法,一个指定被包装组件需要通过props传入的参数数据
     * 一个指定被包装组件需要通过props传入的回调方法
     * connect方法返回的方法接收被包装的组件
     */
    const connect = (mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {
      class Connect extends Component {
        static contextTypes = {
          store: PropTypes.object
        };
        constructor(){
          super()
          this.state = {
            allProps: {}
          }
        }
        componentWillMount(){
          const {store} = this.context
          this._updateProps()
          store.subscribe(() => {
            this._updateProps()
          })
        }
        _updateProps(){
          const {store} = this.context
          let stateProps = mapStateToProps ? mapStateToProps(store.getState(), this.props) : {}
          let dispatchProps = mapDispatchToProps ? mapDispatchToProps(store.dispatch, this.props) : {}
          this.setState(
            {
              allProps: {
                ...stateProps,
                ...dispatchProps,
                ...this.props
              }
            }
          )
        }
        render(){
          return <WrappedComponent {...this.state.allProps}/>
        }
      }
      return Connect;
    }
    
    class Header extends Component{
      static propTypes  = {
        themeColor: PropTypes.string.isRequired
      };
      render(){
        return (
          <h1 style={{color: this.props.themeColor}}>React.js xiaoshu</h1>
        )
      }
    }
    const mapStateToPropsHeader = (state) => {
      return {
        themeColor: state.themeColor
      }
    }
    let CHeader = connect(mapStateToPropsHeader)(Header)
    
    
    class ThemeSwitch extends Component{
      static propTypes = {
        themeColor: PropTypes.string,
        onSwitchColor: PropTypes.func
      }
      handleSwitchColor(color){
        if(this.props.onSwitchColor){
          this.props.onSwitchColor(color)
        }
      }
      render(){
        return (
          <div>
            <button 
              style={{color: this.props.themeColor}}
              onClick = {this.handleSwitchColor.bind(this, "red")}
            >Red</button>
            <button
             style={{color: this.props.themeColor}}
             onClick = {this.handleSwitchColor.bind(this, "blue")}
            >Blue</button>
          </div>
        )
      }
    }
    const mapStateToPropsThemeSwitch = (state) => {
      return {
        themeColor: state.themeColor
      }
    }
    const mapDispatchToPropsThemeSwitch = (dispatch) => {
      return {
        onSwitchColor: (color) => {
          dispatch({ type: 'CHANGE_COLOR', themeColor: color})
        }
      }
    }
    let CThemeSwitch = connect(mapStateToPropsThemeSwitch, mapDispatchToPropsThemeSwitch)(ThemeSwitch)
    
    class Content extends Component {
      render () {
        return (
          <div>
            <p style = {{color: this.props.themeColor}}>React.js 小书</p>
            <CThemeSwitch />
          </div>
        )
      }
    }
    const mapStateToPropsContent = (state) => {
      return {
        themeColor: state.themeColor,
      }
    }
    let CContent = connect(mapStateToPropsContent)(Content);
    
    
    /**
     * Procider是store的载体,通过context提供了让所有子组件访问store中数据的能力
     */
    class Provider extends Component {
      // propTypes 定义了通过创建组件时传入的参数类型,这个功能是通过导入'prop-types'包提供的
      // 如果传入了不是指定类型的参数会报错
      static propTypes = {
        store: PropTypes.object.isRequired,   // isRequired 强制此参数必须传入
        children: PropTypes.any
      }
      // 如果提供了getChildContex方法,则必须提供childContextTypes作为context的声明和验证
      static childContextTypes = {
        store: PropTypes.object
      }
      /**
       * getChildContext方法返回context对象,所有子组件都可以访问context
       * 子组件想要获取context中的内容,就必须写contextTypes来声明和验证要获取的属性的类型
       * static contextTypes = {
       *   themeColor: PropTypes.string
       * };
       */
      getChildContext () {
        return {
          store: this.props.store
        }
      }
      render () {
        return (
          <div>{this.props.children}</div>
        )
      }
    }
    
    /**
     * createStroe接收一个producer函数并返回store对象
     * store对象提供三个方法,getState dispatch subscribe
     * getState() 获取储存在store中的数据
     * dispatch(action) 修改数据(依据action的type属性修改数据)
     * subscribe(listener) 订阅事件,当调用store.dispatch时会收到事件
     */
    function createStore(producer){
      let state = null;
      const listeners = [];
      const subscribe = (listener) => listeners.push(listener);
      const getState = () => state;
      const dispatch = (action) => {
        state = producer(state, action);
        listeners.forEach((listener) => listener());
      };
      dispatch({});
      return {
        getState,
        dispatch,
        subscribe,
      };
    }
    /**
     * 作为参数传入createStore中的reducer函数
     * reducer接收数据和action作为参数并返回修改后的数据
     */
    function themeProducer(state, action){
      if(!state){
        return {
          themeColor: 'red'
        };
      }
      switch(action.type){
        case 'CHANGE_COLOR':
          return {
            ...state,
            themeColor: action.themeColor,
          };
        default:
          return state;
      }
    }
    
    const store = createStore(themeProducer);
    
    class Index extends Component{
      render(){
        return (
          <div>
            <CHeader/>
            <CContent/>
          </div>
        )
      }
    }
    
    ReactDOM.render(
      <Provider store={store}>
        <Index />
      </Provider>,
      document.getElementById('root')
    );
  • 相关阅读:
    《梦断代码》读书笔记(二)
    周总结(十三)
    周总结(十)
    知识圈APP开发记录(十六)
    《梦断代码》读书笔记(一)
    知识圈APP开发记录(十五)
    朴素贝叶斯
    单源最短路径 djkstra
    有向图 拓扑排序 文件依赖下的编译顺序该如何确定?
    《人类简史》读后感
  • 原文地址:https://www.cnblogs.com/ssw-men/p/10870569.html
Copyright © 2011-2022 走看看