对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(
) } }ReactRedux-page
{store.getState()}
store页面
src/store/index.js
import {createStore} from 'redux'
function createReducer(store=1,{type, payload=1}){
// console.log(store)
switch (type) {
case 'ADD':
return store+payload
break;
case 'MINUS':
return store-payload
break;
default:
return store
break;
}
}
const store = createStore(createReducer)
export default store
从而引入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(
,
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(
)
}
}
@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(
ReactRedux-page
{num}
)
}
}
export default ReactRedux
点击的时候直接,直接更新状态;就不再需要去调用生命周期,使用redux的subscribe来进行订阅,更新状态。
connect
的mapDispatchToProps
多种写法
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(
)ReactRedux-page
{num}
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(
ReactRedux-page
{num}
)
}
}
export default ReactRedux
connect
的mergeprops
使用说明(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 }
这个时候,我们来打印看看,现在的agrs是什么?
就是我们在调用add 方法的时候传进来的参数
实现Provider
这个没什么就是用React.createContext();嵌套了一层。这样说话的语气,显得好牛b呀,哈哈哈哈哈哈哈哈,牛死我了
import React from 'react'
const Context= React.createContext()
export function Provider({children, store}){
return {children}
}
实现commit
先搭建一个架子出来
import React from 'react'
export const commit=(
mapStateToProps=state=>state, //这个就是state
mapDispatchToProps // 这个就是整个出来的dispatch
)=>WrappedComponent=>props=>{ // 最后由组建+props,返回一个新的组建
return
}
组建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
实现 mapDispatchToProps
初始化已经完成,还需要实现dispatch方法的实现
如何获取dispatch
我们先打印下store// useContext 读取当前的Context; const store = useContext(Context); console.log('store里面的内容:', store)
还需要主意一个问题,就是当我们去订阅的时候,一定要去取消订阅
我们在什么生命周期里面去调用订阅呢?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
实现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
}
export function Provider({children, store}){
return {children}
}
学习资料
github:https://github.com/speak44/le...
分支是:react-redux