前言
本文章的内容,不会对基础的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(
HookPage
数字:{count}
现在时间:{date.toLocaleTimeString()}
)
}
所有的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(
HookPage2
{state}
)
接下来,我们看函数组建如何使用connect
react 的函数组建,定义组建名大写,里面有return()
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(
ReactReduxHookPage
{num}
)
}
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
}
export function Provider({children, store}){
return {children}
}
// 使用的方法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是不可以的;