React进阶用法和hooks的个人使用见解(Typescript版本) - 4.useReducer+useContext+createContext的使用、模拟redux合并reducer

4.useReducer+useContext+createContext的使用、模拟redux合并reducer

注意:hooks只能在函数(无状态组件)中使用

createContext:一个创建上下文函数,执行产生一个上下文对象,包含两个属性,Provider组件和Consumer组件

Provider:用来包裹整合组件,传递一个value属性,把context上下文注入到整个组件当中
Consumer组件,在里面使用函数调用Provider的value传递的值成形参,并取出使用

具体:官方createContext介绍
useReducer和useContext - Hooks Api链接
useReducer和useContext也不过多介绍了,了解的话可以去官方查看即可,下面直接上代码

4.1useReducer+useContext+createContext的简单使用,创建一个Test.tsx文件

import React, {
      useReducer, useContext, createContext, Context } from 'react';
//初始化stroe的类型、初始化值、reducer
const ADD_COUNTER = 'ADD_COUNTER';
const initialReucer = {
     
    count: 100
}
function reducer(state: typeof initialReucer, action: {
      type: typeof ADD_COUNTER }) {
     
    switch (action.type) {
     
        case ADD_COUNTER:
            return {
      ...state, count: state.count + 1 }
        default:
            return state;
    }
}
const ProviderContext: Context<any> = createContext('provider');//创建上下文实例
//高阶组件,给函数组件注入上下文
const providerHoc = (reducer: Function, initialState: any) => (Com: React.FC<any>) => {
     
    return () => {
     
        const [state, dispatch] = useReducer<any>(reducer, initialState);
        return (
            <ProviderContext.Provider value={
     {
      state, dispatch }}>
                <Com />
            </ProviderContext.Provider >
        );
    }
}
function Test(): JSX.Element {
     
    const {
      state, dispatch } = useContext(ProviderContext);//通过ProviderContext这个上下文实例获取到value,解构出
    console.log(state);
    return (
        <>
            <h2>{
     state.count}</h2>
            {
     /*使用dispatch分发action,触发reducer返回新的state*/}
            <button onClick={
     () => dispatch({
      type: ADD_COUNTER })}>++</button>
        </>
    );
}
export default providerHoc(reducer, initialReucer)(Test);//注入reducer,initialReucer到Test组件中,通过高阶组件对Test组件进行包裹注入
效果:

React进阶用法和hooks的个人使用见解(Typescript版本) - 4.useReducer+useContext+createContext的使用、模拟redux合并reducer_第1张图片

4.2 我们会发现,这样的使用和redux的同步action的情况是一致的,这时候我们可以模拟异步action发送请求获得数据
抽离reducer,, providerHoc, reducer, initialReucer,ADD_COUNTER到store.tsx文件
//stroe.tsx
import React, {
      useReducer, createContext, Context } from 'react';
const ADD_COUNTER = 'ADD_COUNTER';//action-type的类型

export const addActions =()=> ({
      type: ADD_COUNTER });//创建一个同步action

export const initialReucer = {
     //初始化的state
    count: 100
}					//	state的类型,action的类型
export function reducer(state: typeof initialReucer, action: {
      type: typeof ADD_COUNTER }) {
     
    switch (action.type) {
     
        case ADD_COUNTER:
            return {
      ...state, count: state.count + 1 }
        default:
            return state;
    }
}
export const ProviderContext: Context<any> = createContext('provider');//创建上下文实例
//高阶组件,给函数组件注入上下文
export const providerHoc = (reducer: Function, initialState: any) => (Com: React.FC<any>) => {
     
    return () => {
     
        const [state, dispatch] = useReducer<any>(reducer, initialState);
        return (
            <ProviderContext.Provider value={
     {
      state, dispatch }}>
                <Com />
            </ProviderContext.Provider >
        );
    }
}
这时候的test.tsx文件
import React, {
      useContext } from 'react';
import {
      ProviderContext, addActions, providerHoc, reducer, initialReucer } from './store';
function Test(): JSX.Element {
     
    const {
      state, dispatch } = useContext(ProviderContext);//通过ProviderContext这个上下文实例获取到value,解构出
    console.log(state);
    return (
        <>
            <h2>{
     state.count}</h2>
            <button onClick={
     () => dispatch(addActions())}>++</button>
        </>
    );
}
export default providerHoc(reducer, initialReucer)(Test);//注入reducer,initialReucer到Test组件中,通过高阶组件对Test组件进行包裹注入
4.3这样的执行结果当然还是一样的,我们要对代码进行改造
store.tsx如下:
import React, {
      useReducer, createContext, Context, Dispatch } from 'react';
const ADD_COUNTER = 'ADD_COUNTER';

const addActions = () => ({
      type: ADD_COUNTER });//创建一个同步action
// 创建一个异步action的函数,返回一个action对象
const asyncAction = (dispatch: Dispatch<any>) => {
     
    return {
     
        asyncAddaction() {
     //这是一个异步的添加action,定时器模拟异步
        	console.log('执行addActions之前,发送请求 : ' + Date.now());//打印一下时间
            setTimeout(() => {
     
            	console.log('执行addActions ,请求后: ' + Date.now());
                dispatch(addActions());//执行同步action
            }, 1000);
        }
    }
}
export const initialReucer = {
     
    count: 100
}
export function reducer(state: typeof initialReucer, action: {
      type: typeof ADD_COUNTER }) {
     
    switch (action.type) {
     
        case ADD_COUNTER:
            return {
      ...state, count: state.count + 1 }
        default:
            return state;
    }
}
export const ProviderContext: Context<any> = createContext('provider');//创建上下文实例
//高阶组件,给函数组件注入上下文
export const providerHoc = (reducer: Function, initialState: any) => (Com: React.FC<any>) => {
     
    return () => {
     
        const [state, dispatch] = useReducer<any>(reducer, initialState);
        const asyncActions: any = asyncAction(dispatch);//对dispatch进行注入包裹,然后返回
        return (
            <ProviderContext.Provider value={
     {
      state, asyncActions }}>
                <Com />
            </ProviderContext.Provider >
        );
    }
}
test.tsx如下:
import React, {
      useContext } from 'react';
import {
      ProviderContext, providerHoc, reducer, initialReucer } from './store';
function Test(): JSX.Element {
     
    const {
      state, asyncActions } = useContext(ProviderContext);//通过ProviderContext这个上下文实例获取到value,解构出
    const {
      asyncAddaction } = asyncActions;//取出asyncAddaction
    console.log(state);
    return (
        <>
            <h2>{
     state.count}</h2>
            <button onClick={
     () => asyncAddaction()}>++</button>
        </>
    );
}
export default providerHoc(reducer, initialReucer)(Test);//注入reducer,initialReucer到Test组件中,通过高阶组件对Test组件进行包裹注入
执行结果:

React进阶用法和hooks的个人使用见解(Typescript版本) - 4.useReducer+useContext+createContext的使用、模拟redux合并reducer_第2张图片

这样一个简单的异步redux模拟就成功了,相比之下,不用使用redux就是一个很好的实例
下一节我们来了解useRef,useImperativeHandle和forwardRef的结合使用以及useLayoutEffect、useDebugValue的简单使用介绍
还有整合多个reducer的案例,就看另外一个博客把:

模拟redux的combineReducers函数合并reducer,使用createContext, useContext, useReducer整合多个reducer案例(点击跳转到)
npm i redux-custom --save 下载这个小型整合多个reducer的库

其它React进阶用法和hooks的个人使用见解:
React进阶用法和hooks的个人使用见解:
1.lazy+Suspense懒加载的使用
2.hooks的useState、useEffect、自定义钩子的实际使用
3.useCallback+useMemo+memo性能优化
5.useRef,useImperativeHandle和forwardRef的结合使用以及useLayoutEffect、useDebugValue的简单使用

你可能感兴趣的:(react,TypeScript,hooks,React,Typescript,useReducer,useContext)