共计 6911 个字符,预计需要花费 18 分钟才能阅读完成。
前言
本文章的内容,不会对根底的 Hook API 进行解说,比方(能够从官网间接看到)
react Hook API:https://zh-hans.reactjs.org/d…
- useState
- useEffect
- useContext
间接放一个 demo,自行学习吧。也不是很难
import React,{useState,useEffect} from 'react'
export default function HookPage(){const [date, setDate]=useState(new Date())
const [count, setCount] = useState(0)
// 一个函数能够有多个 useEffect
useEffect(() => {console.log('数字产生扭转:' ,count)
}, [count]); // 有依赖项,是 count;所以每次点击更改 count 的时候进行更新,就相当于生命周期 update
useEffect(()=>{console.log('setDate')
const timer = setInterval(()=>{setDate(new Date())
},1000)
// 革除定时器,相当于申明周期 willUnmount
return()=>clearInterval(timer)
},[]) // 没有依赖项,就相当于 DidMount
return(
<div>
<h3>
HookPage
</h3>
<div>
<span>
数字:{count}
</span>
<button onClick={()=>setCount(count+1)}> 减少 </button>
</div>
<div>
当初工夫:{date.toLocaleTimeString()}
</div>
</div>
)
}
所有的 react API 在官网都说的很不错了,我感觉看官网的介绍就曾经很明确了,而且迭代版本必定也是最新的,所以本章的内容次要是联合实战和我的项目,进行简略的应用阐明,之后在进行,手动实现 react-redux 的 Hook API;
useReducer
略微说下这个 API,因为 我在应用 init
的时候,忽略了一个return,导致我查了半天。
import React,{useReducer,useEffect} from 'react'
const creatReduce=(state,{type,payload=1})=>{switch (type) {
case 'ADD':
return state+payload
case 'MINUS':
return state-payload
case 'reset':
return init(payload) // 这里曾经要加 return,要不然里面的 state 拿不到批改后的 state
default:
return new Error()}
}
function init(payload) {console.log('payload',payload);
return payload;
}
export default function HookPage2(){const [state, dispatch] = useReducer(creatReduce, 0, init)
// console.log(creatReduce,'creatReduce')
useEffect(() => {console.log('useEffect',state)
}, [state])
return(
<div>
<h3>
HookPage2
</h3>
<div>
{state}
</div>
<button onClick={()=>{dispatch({type:'ADD'})}}> 点击减少 </button>
<button onClick={()=>{dispatch({type:'reset' ,payload:6})}}> 重置 state</button>
<button onClick={()=>changeswitch()}>swtich 变动 </button>
</div>
)
接下来,咱们看函数组建如何应用connect
react 的函数组建,定义组建名大写,外面有 return(<div></div>)
hook API
useSelctor 获取到 store state
useDispatch 获取 dispatch
import React,{useCallback} from 'react'
import {useSelector, useDispatch} from 'react-redux'
export default function ReactReduxHookPage(){const num = useSelector(state => state)
const dispatch = useDispatch()
const add=useCallback(()=>{dispatch({type:'ADD'})
},[])
console.log(num,'num')
return(
<div>
<h3>
ReactReduxHookPage
</h3>
<div>
{num}
</div>
<button onClick={add}>add</button>
</div>
)
}
useCallback
用于缓存inline
函数,缓存函数;避免因属性更新时生成新的函数导致子组件反复渲染
接下来咱们来实现自定义 hook 办法
还是写在门路:src/MyReactRedux.js
中
实现 useSelctor
咱们先来一个根本搭建
const Context= React.createContext() export function useSelector(){ // 首先要获取到 store;用自定义的办法来获取 context 的值;用 useContext} // 自定义 hook,来获取 state export function useStore(){ // 须要 use 结尾,大写字母;不能自己瞎定义自定义 hook 的名字 const store =useContext(connect) }
完整版的实现:
// 应用的办法 const num = useSelector(state => state)
// 先将参数传进来
export function useSelector(selector){ // 首先要获取到 store;用自定义的办法来获取 context 的值;用 useContext
// 最终须要实现的是 getState
//1. 获取到 store
const store =useStore()
//2. 从 store 中获取到 getState
console.log('useSelector 的 store', store)
const {getState} = store
// 获取到 state 进行返回;selector 传进来的是一个函数‘state => state’;getState()将作为 selector 函数的参数进行返回
const selectState = selector(getState()) //getState()的执行,是返回以后的 state
console.log('selectState:',selectState)
return selectState
}
// 自定义 hook,来获取 state
export function useStore(){ // hook 的定义方法,须要 use 结尾,大写字母
const store =useContext(Context)
return store
}
让咱们看下打印后果:获取到了以后的值。
实现 useDispatch
根本搭建
export function useDispatch(){}
首先先明确 useDispatch 的返回值:
// 咱们的应用形式:const dispatch = useDispatch()
export function useDispatch(){
// 指标是返回一个 dispatch 办法
// 1. 先获取 dispatch
const store =useStore()
// 间接返回
return store.dispatch
}
// 自定义 hook,来获取 state
export function useStore(){ // hook 的定义方法,须要 use 结尾,大写字母
const store =useContext(Context)
return store
}
当初咱们这样写 useDispatch,当咱们点击页面的点击事件‘add’ 的时候,会发现,页面是没有变动的。是因为咱们触发了 dispatch,却没有驱动页面进行刷新来进行批改。所以会存在页面没有刷新的状况。所以咱们还须要在 useSelector 中去订阅,当 state 变动的时候进行页面回流。
实现 加强版的useSelctor
,订阅和勾销订阅
// 应用的办法 const num = useSelector(state => state)
// 先将参数传进来
export function useSelector(selector){ // 首先要获取到 store;用自定义的办法来获取 context 的值;用 useContext
// 最终须要实现的是 getState
//1. 获取到 store
const store =useStore()
//2. 从 store 中获取到 getState
console.log('useSelector 的 store', store)
const {getState,subscribe} = store
const selectState = selector(getState()) //getState()的执行,是返回以后的 state
// 定义 forceUpdate
const [ignored, forceUpdate] = useReducer(x=>x+1,0)
// 当 store 批改的时候,调用 useLayoutEffect;useLayoutEffect(() => {const unsubscribe =subscribe(()=>{forceUpdate()
})
return () => {if(unsubscribe){unsubscribe()
}
};
},[store])
// 获取到 state 进行返回;selector 传进来的是一个函数‘state => state’;getState()将作为 selector 函数的参数进行返回
console.log('selectState:',selectState)
return selectState
}
useLayoutEffect 的应用和介绍官网有,我的上一篇文章
react-Redux 的 API 的应用及原理解说和手动实现办法
也有具体的阐明和介绍;就是将 react-redux 的组建 API 和 Hook API 进行了离开解说。能够对照着来学习
hook 的益处
自定义 hook 的益处就是能够共享逻辑,实现逻辑的复用 还须要留神 hook 办法只能用到 hook 办法当中去或者是函数组建中。本人写一个函数去应用 hook 是不能够的;
MyReactRedux 的残缺版本
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>
}
// 应用的办法 const num = useSelector(state => state)
// 先将参数传进来
export function useSelector(selector){ // 首先要获取到 store;用自定义的办法来获取 context 的值;用 useContext
// 最终须要实现的是 getState
//1. 获取到 store
const store =useStore()
//2. 从 store 中获取到 getState
console.log('useSelector 的 store', store)
const {getState,subscribe} = store
const selectState = selector(getState()) //getState()的执行,是返回以后的 state
// 定义 forceUpdate
const [ignored, forceUpdate] = useReducer(x=>x+1,0)
// 当 store 批改的时候,调用 useLayoutEffect;useLayoutEffect(() => {const unsubscribe =subscribe(()=>{forceUpdate()
})
return () => {if(unsubscribe){unsubscribe()
}
};
},[store])
// 获取到 state 进行返回;selector 传进来的是一个函数‘state => state’;getState()将作为 selector 函数的参数进行返回
console.log('selectState:',selectState)
return selectState
}
// 咱们的应用形式:const dispatch = useDispatch()
export function useDispatch(){
// 指标是返回一个 dispatch 办法
// 1. 先获取 dispatch
const store =useStore()
// 间接返回
return store.dispatch
}
// 自定义 hook,来获取 state
export function useStore(){ // hook 的定义方法,须要 use 结尾,大写字母
const store =useContext(Context)
return store
}
// 自定义 hook 的益处就是能够共享逻辑,实现逻辑的复用 还须要留神 hook 办法只能用到 hook 办法当中去或者是函数组建中。本人写一个函数去应用 hook 是不能够的;