美文网首页
简单实现react-redux

简单实现react-redux

作者: 西洲何在 | 来源:发表于2018-04-10 14:20 被阅读0次

    前言

    实现自己的miniredux中,我简单的做出了一个具备redux几个功能的miniredux,如果直接在react中使用的话,复杂又累赘,那么如何优雅的在react中使用自己的miniredux呢?自然就是实现react-redux了!

    一、react的react-redux库的使用

    在实现自己的react-redux前,我们先看看react的库react-redux是如何使用的。

    我们先创建一个reducer.js

    const ADD_GUN = '加一'
    const MINUS_GUN = '减一'
    const initstate = {
      num: 10
    }
    export function counter(state = initstate, action) {
      switch(action.type) {
        case ADD_GUN:
          return {...state, num: state.num + 1}
        case MINUS_GUN:
          return { ...state, num: state.num - 1 }
        default:
          return state
      }
    }
    
    export function add() {
      return { type: ADD_GUN }
    }
    
    export function minus() {
      return { type: MINUS_GUN }
    }
    

    然后在react的入口文件index.js里引入这个store

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    import registerServiceWorker from './registerServiceWorker';
    import { createStore } from 'redux'
    import { counter } from './redux/reducer'
    import { Provider } from 'react-redux'
    
    const store = createStore(counter)
    
    ReactDOM.render(<Provider store={store}>
      <App /></Provider>, document.getElementById('root'));
    registerServiceWorker();
    

    这里我们可以看到,从react-redux中引入了一个Provider组件,它将store传入到下级子组件,供所有子组件使用

    我们在App组件使用store,就要引入action,然后把redux的state直接传入组件的props,这样就能优雅的使用redux数据了

    import React,{ Component } from 'react'
    import { connect } from 'react-redux'
    // redux action
    import { add, minus } from '../redux/reducer'
    
    class App extends Component {
      componentDidMount() {
      }
      render () {
        return (
          <div>
            <h3>{this.props.num}</h3>
            <button onClick={() => {
              this.props.add()
            }}>加一</button>
            <button onClick={() => {
              this.props.minus()
            }}>减一</button>
          </div>
        )
      }
    }
    
    App = connect(
      state => state,
      { addgun, minusgun }
    )(App)
    
    export default App 
    

    在这里我们用react-redux的connect发放将redux里的action和state映射到App的props里,这样就可以优雅的使用redux的数据了

    所以我们可以看出,实际我们在这里就是要实现Provider组件和connect方法,就可以在子组件里使用redux数据了

    二、实现Provider

    实际上Provider组件提供了一个全局变量,这个全局变量将redux的state,dispatch和subscribe方法暴露给所有子组件,不过在react的设计模式里认为这并不是一个好的方法,所以要对全局变量进行严格的类型检查。所以我们要使用到react的类型检查库prop-types。

    那么在react怎么设置这个全局变量呢?react有个自带的属性context,这个属性就是用来暴露全局变量的。

    我们先安装prop-types库

    $npm install prop-types --save
    

    然后我们新建一个my-react-redux.js文件

    import React, { Component } from 'react'
    import PropTypes from 'prop-types'
    
    export class Provider extends Component {
      // 设置子组件context的类型,以便子组件的类型检查
      static childContextTypes = {
        store: PropTypes.object
      }
      // 传递到子组件的全局context
      getChildContext() {
        return {store: this.store}
      }
      // 初始化props和context
      constructor(props, context) {
        super(props, context)
        this.store = props.store
      }
      render() {
        return this.props.children
      }
    }
    

    这里实现了Provider,实际上已经能够在子组件里使用redux了,但是依旧麻烦和冗杂,connect才是把redux映射到子组件props的关键

    三、实现connect

    在my-react-redux.js中继续实现connect

    /**
     * connect函数实现Provider里的redux向使用redux组件里传递的功能
     * 实际connect函数就是实现一个中间件的功能,避免子组件复杂的操作redux的方法
     * 而能够直接在子组件的props里调用到redux的方法和数据
     * @param {Function} mapStateToProps 把redux的state数据添加到子组件的props里
     * @param {Object} mapDispatchToProps 把redux的action方法添加到props里
     * @returns 返回一个react组件
     */
    export const connect = (mapStateToProps=state=>state, mapDispatchToProps={}) => {
      return (Comp) => {
        return class MiddleComp extends Component {
          static contextTypes = {
            store: PropTypes.object
          }
          constructor(props, context) {
            super(props, context)
            this.state = {
              props: {}
            }
          }
          componentWillMount() {
            const {store} = this.context
            // 监听state的变化
            store.subscribe(() => this.update())
            // 初始化redux
            this.update()
          }
          // 要想action执行,改变state,只有dispatch后才能真正执行了action
          // 因此这里我们把action先包装在dispatch里,再加上一个包装,放进
          // bound统一返回
          actionToBindDisptch(creators, dispatch) {
            let bound = {}
            Object.keys(creators).forEach((v) => {
              let creator = creators[v]
              bound[v] = (...args) => {return dispatch(creator(...args))}
            })
            return bound
          }
          update() {
            const { store } = this.context
            const stateProps = mapStateToProps(store.getState())
            const dispatchProps = this.actionToBindDisptch(mapDispatchToProps, store.dispacth)
            this.setState({
              props: {
                ...this.state.props,
                ...stateProps,
                ...dispatchProps
              }
            })
          }
          render() {
            return  <MiddleComp {...this.state.props}></MiddleComp>
          }
        }
      }
    }
    

    到此,我们就实现了一个简单的react-redux,它的使用和react的库react-redux没有区别,当然connect的实现我们使用了react的高阶组件,有兴趣的朋友可以了解

    相关文章

      网友评论

          本文标题:简单实现react-redux

          本文链接:https://www.haomeiwen.com/subject/ukjghftx.html