zoukankan      html  css  js  c++  java
  • Redux和React-Redux的实现(一):Redux的实现和context

    react使用redux做状态管理,实现多个组件之间的信息共享,解决了父子组件、兄弟组件之间的复杂通信问题。vue有vuex,总之是一种flux的思想。react提供了react-redux这个库,一看名字就知道是为了将react和redux关联起来,react-redux有connect高阶函数以及Provider组件、milddleware、thunk等,来实现一下。

    篇幅过长,多分了几篇。

    1. Redux简单实现


    这里先不考虑中间件机制

    import { createStore } from 'redux'
    
    function counter(state = 10, action) {
      console.log(state, action)
      switch (action.type) {
        case 'add':
          return state + 1
        case 'less':
          return state - 1
        default:
          return state
      }
    }
    
    const store = createStore(counter)
    
    const init = store.getState()
    console.log(`Init count: ${init}`)
    
    function listener(){
      const current = store.getState()
      console.log(`count: ${current}`)
    }
    store.subscribe(listener)
    
    store.dispatch({ type: 'add' })
    store.dispatch({ type: 'less' })
    

    这是redux简单的例子,首先我们定义了一个reducer叫做counter,接下来使用redux提供的createStore方法将reducer传入,构造出了一个store,然后基于观察者模式,触发相应的action,进行相应的响应。

    Redux重点的方法就是createStore、getState、subscribe、dispatch这四个方法。大体讲一下思路,我们的Redux,这里就叫myRedux,myRedux和Redux一样,都是只暴露出来一个方法,那就是createStore,然后createStore保存着一个state,可以是对象、字符串、数组等,可以通过getState方法来访问state,还有对state的监听器以及订阅的方法,实现一下。

    export function createStore (reducer) {
      let state = {}
      let listeners = []
    
      function getState () {
        return state
      }
      function subscribe (listener) {
        listeners.push(listener)
      }
      function dispatch (action) {
        state = reducer(state, action)
        listeners.forEach(listener => listener())
        return action
      }
      // 为了确保createStore之后,store.getState中就有state的初始值
      dispatch({type: '@myRedux/qwe'})
      return {getState, subscribe, dispatch}
    }
    

    其实就是一个观察者模式,值得注意的是:当执行完createStore之后,执行stroe.getState方法就能获取到初始的状态(我们这里是10),所以需要我们的reducer先执行一次,那么我们就要在createStore中就先dispatch一下,代码中有体现。Redux中也是这么做的,Redux初始化dispatch的type值是@@redux/INIT,可以看一下。

    这么做是为了确保初始化dispatch的type值不会和用户定义的type值重复,我们代码里type为@myRedux/qwe

    2.react中的context


    要理解react-redux原理,必须先说下react中的context。父组件向子组件传递数据,可以通过props,如果层级比较深呢?就不好了,会有性能问题,我们可以通过context来实现跨级传递数据。

    context是全局的,在组件中声明,所有的子组件都可以获取到context,react觉得全局不是很安全,所以要求context都是强数据类型,即任何想访问context里面的属性的组件都必须指定一个contextTypes的属性,如果没有指定该属性的话,用this.context访该属性就会出错。

    同样,通过getChildContext方法指定传递给子组件的属性也需要被指定数据类型,通过childContextTypes来指定,不指定同样会产生错误。

    下面是一个简单例子。

    import React from 'react'
    import PropTypes from 'prop-types'
    
    class Son extends React.Component{
    	render(){
    			return (
    				<div>
    					<p>子组件</p>
    					<GrandSon/>
    				</div>
    			)
    	}
    }
    
    class GrandSon extends React.Component{
    	static contextTypes = {
    		user:PropTypes.string
    	}
    	render(){
    		console.log(this.context)
    		return (
    				<div>
    					<p>孙组件</p>
    					<div>孙组件收到来自父组件的信息:{this.context.user}</div>
    				</div>
    		)
    	}
    }
    
    class Father extends React.Component{
    	static childContextTypes = {
    		user:PropTypes.string
    	}
    	constructor(props){
    		super(props)
    		this.state = {user:'user12'}
    	}
    	getChildContext(){
    		return this.state
    	}
    	render(){
    		return (
    			<div>
    				<p>父组件,要给孙组件:{this.state.user}</p>
    				<Son/>
    			</div>
    		)
    	}
    }
    
    export default Father
    

    在这里就不需要通过props一层一层的往下传递属性了,这就是context。

    3.Provider组件


    那么context和我们的react-redux有什么关系呢,用过的都知道,Provider组件在整个应用组件上包了一层,让整个应用组件成为Provider的子组件,看到这里,你是不是有点懂了,跟上面的例子很像嘛,对的,就是这样,我们的Provider组件接收Redux的store作为props,通过context对象传递给子组件。

    我们下一篇就会说道Provider组件。

  • 相关阅读:
    hdu 5101 Select
    hdu 5100 Chessboard
    cf B. I.O.U.
    cf C. Inna and Dima
    cf B. Inna and Nine
    cf C. Counting Kangaroos is Fun
    Radar Installation 贪心
    spfa模板
    Sequence
    棋盘问题
  • 原文地址:https://www.cnblogs.com/isLiu/p/8117427.html
Copyright © 2011-2022 走看看