乐趣区

reactRedux的API的使用及原理讲解和手动实现方法

对 react-Redux 的利用与了解

在平时中,咱们间接去应用 Redux,须要每个页面都须要引入 store,执行 getState()来获取到值,以及须要每次都进行订阅和勾销订阅。保护起来不不便

import React,{Component} from 'react'
import store from '../store'
export default class ReactRedux extends Component{constructor(){super()
  }
  componentDidMount(){// 挂载
    this.unsubscribe=store.subscribe(()=>{this.forceUpdate()
    })
  }
  add=()=>{store.dispatch({type:'ADD',payload:10})
  }
  componentWillUnmount(){// 卸载
    if(this.unsubscribe){this.unsubscribe()
    }
  }
  render(){
    return(
      <div>
        <h3>ReactRedux-page</h3>
        <div>
          <p>{store.getState()}</p>
          <button
            onClick={this.add}
          >
            add
          </button>
        </div>
      </div>
    )
  }
}
从而引入 react-Redux,Provider 这个性能;在根目录下间接引入 store;

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import ReactRedux from './pages/ReactReduxPage'
import {Provider}  from 'react-redux'
import store from './store'

ReactDOM.render(<Provider store={store}>
    <ReactRedux />
  </Provider>
 ,
  document.getElementById('root')
);

class 组建在应用 connect 引入

import {connect} from 'react-redux'

connect 一共有三个参数:state,dispatch,mergeProps(将 props 进行合并)

@connect((state)=>({num:state})
)
class ReactRedux extends Component{render(){console.log(this.props)
      return(<div></div>)
   }
}

@connect 是装璜器的应用,或者能够export default connect()(class ...); 装璜器的应用能够本人查下不做重点解说。

打印this.props

能够看到 传进来的 state 值,以及 dispatch;咱们能够在 porps 中拿到。

import React,{Component} from 'react'
import store from '../store/'
import {connect} from 'react-redux'
@connect((state)=>({num:state})
)
class ReactRedux extends Component{constructor(){super()
  }
  add=()=>{this.props.dispatch({type:'ADD',payload:10})
  }
  render(){const {num, dispatch} = this.props
    console.log(this.props,'this.props')
    return(
      <div>
        <h3>ReactRedux-page</h3>
        <div>
          <p>{num}</p>
          <button
            onClick={this.add}
          >
            add
          </button>
        </div>
      </div>
    )
  }
}
export default ReactRedux

点击的时候间接,间接更新状态;就不再须要去调用生命周期,应用 redux 的 subscribe 来进行订阅, 更新状态。

connectmapDispatchToProps 多种写法

dispatch 能够是对象 也能够是函数;

对象写法

@connect(
  //store
  (state)=>({num:state}),
  // dispatch 类型:obj|fn
  {add:()=>({
      type:'ADD',
      payload:20
    })
  }
)

函数写法

  dispatch=>{const add =()=>dispatch({type:'ADD', payload:20})
    const minus=()=>dispatch({type:'MINUS', payload:10})
    return {dispatch,add ,minus}
  }

或者应用import bindActionCreators from 'redux'

最初整合进去,的后果和下面的写法是一样的,只是上面应用 bindActionCreators 来进行了整合

  dispatch=>{// const add =()=>dispatch({type:'ADD', payload:20})
    // const minus=()=>dispatch({type:'MINUS', payload:10})
    // 这个写法和申明正文的写法是一样的
    let creators={add:()=>({type:'ADD', payload:20}),
      minus:()=>({type:'MINUS', payload:10})
    }
    creators=bindActionCreators(creators, dispatch)
    return {dispatch,...creators}
  }

props 将会上挂载了 add、minus 和 dispatch 办法;

应用:

 Dispatchadd=()=>{this.props.dispatch({type:'ADD',payload:10})
 }

render(){const {num, add,minus} = this.props
  console.log(this.props,'this.props')
  return(
    <div>
      <h3>ReactRedux-page</h3>
      <div>
        <p>{num}</p>
        <button onClick={this.Dispatchadd}>Dispatchadd+10</button>
        <button onClick={add}>add+20</button>     
        <button onClick={minus}>minus-10</button>
      </div>
    </div>
  )

mapDispatchToProps 的总结
写法一:function 间接能够将 dispatch 返回;

dispatch=>{
// 在外面定义其余的 disaptch 办法
return (dispatch,其余 dispatch 办法)
}

写法二:object 间接定义 dispatch,然而组建中,就只能去调用定义的办法名字,不能去应用 this.props.dispatch

 {add:()=>({
     type:'ADD',
     payload:20
   })
 }
import React,{Component} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
@connect(
  // 将 state 放在 props 上一份;` 参数一:mapStateToProps`
  (state)=>({num:state}),
  ` 参数二:mapDispatchToProps`
  // dispatch 类型:obj|fn 将 dispatch 放在 poros 上一份;mapDispatchToProps
  // dispatch 写法一:不含自身的 dispatch,只能调用对象外面写的办法;// {//   add:()=>({
  //     type:'ADD',
  //     payload:20
  //   })
  // }
  // dispatch 写法二:(dispatch,ownProps)=>{ 
  // ownProps 是指的,当传进来的 props 进行了批改,每一次都会加载一遍;//ownProps 能够不写,写了只不过是每次当 props 批改的时候,就会调用这个办法
  
    // 办法一:间接这样写,到导出
    // const add =()=>dispatch({ type:'ADD', payload:20})
    // const minus=()=>dispatch({type:'MINUS', payload:10})
    // return {dispatch, add, minus}
    // 办法二:应用 bindActionCreators 来进行合并
    let creators={add:()=>({type:'ADD', payload:20}),
      minus:()=>({type:'MINUS', payload:10})
    }
    creators=bindActionCreators(creators, dispatch)
    return {dispatch,...creators}
  },
  ` 参数三:mergeprops`,解说在最初,拿出来说,其实并不怎么罕用
  (stateProps,dispatchProps,ownProps)=>{
    return {
      ...stateProps,
      ...dispatchProps,
      ...ownProps
    }
  }
)
class ReactRedux extends Component{constructor(){super()
  }
  Dispatchadd=()=>{this.props.dispatch({type:'ADD',payload:10})
  }
  
  render(){const {num, add,minus} = this.props
    console.log(this.props,'this.props')
    return(
      <div>
        <h3>ReactRedux-page</h3>
        <div>
          <p>{num}</p>
          <button onClick={this.Dispatchadd}>Dispatchadd+10</button>
          <button onClick={add}>add+20</button>     
          <button onClick={minus}>minus-10</button>       
        </div>
      </div>
    )
  }
}
export default ReactRedux
connectmergeprops 应用阐明
 (stateProps,dispatchProps,ownProps)=>{
   return {
     ...stateProps,
     ...dispatchProps,
     ...ownProps
   }
 }

打印 this.props 的值

dispatch 和 state


当 在 return 外面自定义了内容时,props 的打印后果

 (stateProps,dispatchProps,ownProps)=>{
   return {
     ...stateProps,
     ...dispatchProps,
     ...ownProps,
     own:'自定义内容'
   }
 }

如果在 return 外面删除 stateProps,或者 dispatchProps;
this.props 也会随之缺失


mapDispatchToProps的函数写法上,去整合 dispatch 引入了一个 bindActionCreators,当初咱们本人实现一下试试。

实现bindActionCreators

import {bindActionCreators} from 'redux'

这个是 redux 的 api,bindActionCreators的作用是将一个或多个 action 和 dispatch 组合起来生成 mapDispatchToProps 须要生成的内容。

function bindActionCreator(creator,dispatch){// console.log(creator,'creator')
  return (...args) => {console.log(args,'...args') // 函数在 onClick 调用的时候传递进来的参数
    dispatch(creator(...args))
  }
}

// 接管两个参数 creators, dispatch
export function bindActionCreators(creators, dispatch){console.log(creators,'creators')
  // 定一个一个空的对象
  let obj={} // 用来导出
  // 首先须要遍历进去,给每一项加上 dispatch;for(let key in creators){obj[key] = bindActionCreator(creators[key],dispatch)
  }
  console.log(obj,'obj')
  return obj
}

阐明:

  • bindActionCreators 导出的还是一个对象,是用 dispatch 整合进去的对象。所以最初 return obj
  • for…in 将每一个穿进来的对象,用 dispatch 在包一层
  • args 是从何而来?

    咱们当初批改 add 叠加的形式:

       let creators={add:(num)=>({type:'ADD',...num}),
         minus:()=>({type:'MINUS', payload:10})
       }

    num 是办法在调用的时候传进来的参数

    class ReactRedux extends Component{render(){const {num} = this.props
       <button onClick={()=>{add({payload:20})}}>add+20</button> 
     }

    这个时候,咱们来打印看看,当初的 agrs 是什么?

    就是咱们在调用 add 办法的时候传进来的参数

实现Provider

这个没什么就是用 React.createContext(); 嵌套了一层。这样谈话的语气,显得好牛 b 呀,哈哈哈哈哈哈哈哈,牛死我了

import React from  'react'

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

实现commit

先搭建一个架子进去
import React from  'react'

export const commit=(
  mapStateToProps=state=>state, // 这个就是 state
  mapDispatchToProps // 这个就是整个进去的 dispatch
)=>WrappedComponent=>props=>{ // 最初由组建 +props,返回一个新的组建
  return<WrappedComponent {...props}/>
}
组建 stateProps 的获取
   // 首先要获取到传递进来的 stateToProps
   // state 的获取是从 mapStStateToProps 而来的
    const stateProps = mapStateToProps(这里的 state 从何而来) 
    //mapStateToProps 是一个函数传进来一个 state,导出一个 state;
mapStateProps 的参数 state 如何获取

首先明确,咱们以后的组建,是一个函数组建
那函数组建如何获取 state?通过 getState 来获取,getState 在 store 外面;联合上下文,咱们须要用到 useContext 来获取;

  // useContext 读取以后的 Context;const store = useContext(Context);
  // 从 store 中去获取 store
  const {getState} =store
  const stateProps = mapStateToProps(getState())
  return<WrappedComponent {...props} {...stateProps}/>
实现 mapDispatchToProps

初始化曾经实现,还须要实现 dispatch 办法的实现
如何获取 dispatch
咱们先打印下 store

 // useContext 读取以后的 Context;const store = useContext(Context);
 console.log('store 外面的内容:', store)


从而得悉,dispatch 能够从 store 中获取。
接下来思考如何更新;dispatch 之后组建为更新,所以用订阅 subscript 调用forceUpdate 来更新组建
在函数组建中,咱们应用 useReduce 来实现forceUpdate 函数,在官网中有记录。
有相似 forceUpdate 的货色吗?:https://zh-hans.reactjs.org/d…

还须要主见一个问题,就是当咱们去订阅的时候,肯定要去勾销订阅
咱们在什么生命周期外面去调用订阅呢?

useEffect 还是 useLayoutEffect 中去应用?


看介绍能够得悉,useLayoutEffect 的调用要比 useEffect 更为提前
useEffect 存在提早;如果组建在 constructor 中就有了订阅和更新,那么 useEffect 就会失落。
所以咱们应用 useLayoutEffect

const {getState, dispatch, subscribe} =store

const dispatchProps={dispatch}
  const [ignored, forceUpdate] = useReducer(x=>x+1,0)
  useLayoutEffect(() => {  // 相当于 componentDidMount;useLayoutEffect 要比 useEffect 要提前执行
    // 订阅
    const unsubscribe =subscribe(()=>{forceUpdate()// 刷新状态
    })
    return () => { // 相当于 componentWillUnmount
      // 勾销订阅
      if(unsubscribe){unsubscribe()
      }
    }
  }, [store]) // 关联 store 变动时触发
  
  return <WrappedComponent {...props} {...stateProps} {...dispatchProps}/>
实现mapDispatchToProps
  • 从下面的案例得悉,mapDispatchToProps有两种展示模式,一种是对象,一种是函数。
  • 咱们先打印看下 当 mapDispatchToProps 是函数 的状况,是什么?

所以 能够得出结论,如果是函数的时候,间接穿参 dispatch,执行 mapDispatchToProps 函数就能够

  • 如果 mapDispatchToProps 是对象,打印后果

外面是一个对象,咱们只须要将它用 bindActionCreators 进行封装之后在返回就能够。

  let  dispatchProps={ // 定义变成 let,上面会依据 mapDispatchToProps 来进行反复赋植
    dispatch
  }
  // console.log('dispatchProps',dispatchProps);
  // console.log('mapDispatchToProps',mapDispatchToProps)
  // 首先进行类型的判断
   if (typeof mapDispatchToProps === 'function') {
     // 如果是函数,就将 diapatch 传进去,之后执行函数在返回
      dispatchProps =mapDispatchToProps(dispatch)
   } else if (typeof mapDispatchToProps === 'object'){
     // 如果是对象,就调用 bindActionCreators,将对象进行封装返回
     dispatchProps =bindActionCreators(mapDispatchToProps,dispatch)
   }

react-redux的实现残缺代码

门路:src/MyReactRedux.js

import React,{useContext,useReducer,useLayoutEffect} from  'react'
import {bindActionCreators} from './MybindActionCreators'
const Context= React.createContext()
export const connect=(
  mapStateToProps=state=>state,
  mapDispatchToProps
)=>WrappedComponent=>props=>{
  
  // useContext 读取以后的 Context;const store = useContext(Context);
  // 从 store 中去获取 store
  const {getState, dispatch, subscribe} =store

  // 首先要获取到传递进来的 stateProps
  // state 的获取是从 mapStateToProps 而来的
  const stateProps = mapStateToProps(getState()) //mapStateToProps 是一个函数传进来一个 state,导出一个 state;let  dispatchProps={ // 定义变成 let,上面会依据 mapDispatchToProps 来进行反复赋植
    dispatch
  }
  // console.log('dispatchProps',dispatchProps);
  // console.log('mapDispatchToProps',mapDispatchToProps)
  // 首先进行类型的判断
   if (typeof mapDispatchToProps === 'function') {
     // 如果是函数,就将 diapatch 传进去,之后执行函数在返回
      dispatchProps =mapDispatchToProps(dispatch)
   } else if (typeof mapDispatchToProps === 'object'){
     // 如果是对象,就调用 bindActionCreators,将对象进行封装返回
     dispatchProps =bindActionCreators(mapDispatchToProps,dispatch)
   }

  const [ignored, forceUpdate] = useReducer(x=>x+1,0)
  useLayoutEffect(() => {  // 相当于 componentDidMount;useLayoutEffect 要比 useEffect 要提前执行
    // 订阅
    // console.log('useLayoutEffect')
    const unsubscribe =subscribe(()=>{forceUpdate()// 刷新状态
    })
    return () => { // 相当于 componentWillUnmount
      // 勾销订阅
      if(unsubscribe){unsubscribe()
      }
    }
  }, [store]) // 关联 store 变动时触发
  return <WrappedComponent {...props} {...stateProps} {...dispatchProps}/>
}

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

学习材料

github:https://github.com/speak44/le…
分支是:react-redux

退出移动版