React中Context(createContext)与useReducer的结合使用,功能类似redux

目录

作用:

createContext 的使用步骤:

useReducer的使用步骤:


作用:

createContex + useReducer 约等于 redux

createContext的作用: 跨组件通信

useReducer的作用: 存储数据,通过dispatch改变数据

createContext 的使用步骤:

1,在context.ts 创建Context对象

import { createContext } from "react";

// 1. 创建Context对象
export default createContext({} as any);

2, 在Provider.tsx中

1)导入context.ts

2)Provider来包裹后代组件,跨组件传递数据
在Provider.tsx创健Provider,也就是context.Provider,提供数据contextValue

数据contextValue 由useReducer提供并且管理(后续讲)

import React, { useReducer, useMemo, createContext } from 'react';
import context from './context';
import reducer from './reducer';
import initial from './initial';

export default ({children}: any) => {
  const [state, dispatch] = useReducer(reducer, initial);
  const contextValue = useMemo(() => ({
    state,
    dispatch,
  }), [
    state
  ]);
return (
    <context.Provider
      value={contextValue}
    >
      {children}
    </context.Provider>
  );
}

3.被provider包裹的组件如何拿到数据呢?--跨组件通信

1)通过Provider 包裹后代组件

--1, 导入Provider

--2,被Provider包裹的组件都嫩拿到contextValue的数据

---3 包裹的组件:Son1 (Son1里面还有Son2)

import React, { useContext } from 'react'
import './App.less'
import {Son1} from './Son1'
import Provider from './context/Provider'
import context from './context/context'

export const Header:React.FC =() => {
   const {dispatch, state} = useContext(context)
   console.log(state); //undefined 注意此组件不能拿到数据,因为没有被Provider包裹
    return (
      <>
      <Provider>
         <div className='head'>
            <span>我最大</span>
            <Son1></Son1>
         </div>
      </Provider>
       </>
    )
  }

2)后代组件如何拿到数据
--1,导入context.ts

--2,通过useContext 拿到数据state即可

import React, { useContext } from 'react'
import './App.less'
import { Son2 } from './Son2'
import context from './context/context'


export const Son1:React.FC =() => {
   const {dispatch, state} = useContext(context)
    return (
      <>
      <div className='Son1'>
         <div>我是Son1,我也拿到值:{state.numberValue}</div>
         <Son2></Son2>
      </div>
       </>
    )
  }

useReducer的使用步骤:

1)在initial创建初始数据state

//准备初始数据
export default {
    numberValue: 0,
  };

2)创建reducer
state 就是初始数据,action为dispatch的action,dispatch(action)

action为 {type:xxx, payload: xxx }

export default (state: any, action: any) => {
    switch (action.type) {
        case "change2":
            return {
                ...state,
                numberValue: action.payload
            };
        default:
            return {
                ...state,
                numberValue:222
            };
    }
}

3)在Provider中,创建useReducer

useReducer有2个参数,参数1 为reducer,参数2 为初始数据

拿到初始数据与dispatch,我们可以把数据传递给后代组件

import React, { useReducer, useMemo, createContext } from 'react';
import context from './context';
import reducer from './reducer';
import initial from './initial';

export default ({children}: any) => {
  const [state, dispatch] = useReducer(reducer, initial);
  const contextValue = useMemo(() => ({
    state,
    dispatch,
  }), [
    state
  ]);
return (
    <context.Provider
      value={contextValue}
    >
      {children}
    </context.Provider>
  );
}

4)看看如何通过dispatch改变数据的

点击按钮,dispatch派遣action,即可改变数据,组件也拿到了改变后的数据

import React, { useContext } from 'react'
import './App.less'
import context from './context/context'

export const Son2:React.FC =() => {
   const value = useContext(context)
   console.log('value',value);//{ dispatch, state: {numberValue: ?} }
   const {dispatch, state:{numberValue}} = value

   const addNumber = () =>  {
      dispatch({
         type:'change2',
         payload:2
      })
   }
    return (
      <>
      <div className='Son2'>
         我是Son2, Provider中的值{numberValue}
         <button onClick={addNumber}>点击变成2 </button>
      </div>
       </>
    )
  }

点击后

优化:对reducer进行分类封装

chang2.ts

export default (state: any, action: any) => {
    state.numberValue = action.payload
    return state;
}

 index.ts

import change2 from './change2';

export default{
    change2,
}

reducer.ts 

//写法1,直接写
// export default (state: any, action: any) => {
//     switch (action.type) {
//         case "change2":
//             return {
//                 ...state,
//                 numberValue: action.payload
//             };
//         default:
//             return {
//                 ...state,
//                 numberValue:222
//             };
//     }
// }

//写法2,用写法1注解下面的写法2即可
import lodash from 'lodash';
import reducers from './reducers'
import produce from 'immer'

interface Reducers {
    [key: string]: (state: any, action: any) => any;
  }

export default (state: any, action: any) => {
  const reducer = (reducers as Reducers)[action.type];
   //拿到函数
    // const reducer = (state: any, action: any) => {
    //     state.numberValue = action.payload
    //     return state;
    // }
  if (lodash.isFunction(reducer)) {
    return produce(state, (draftState: any) => {
        //复制state为draftState ,传入reducer中
      return reducer(draftState, action)
    });
  }
  return state;
};
  • 页面state简单,可以直接使用useState
  • 页面state复杂,state是一个对象或者state非常多散落在各处, 使用userReducer
  • 页面组件层级比较深,并且需要子组件触发state的变化,可以考虑useReducer + useContext
  • 13
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值