react之useContext、useReducer

本文详细介绍了React中如何利用useContext进行组件间的状态穿透和通信,以及在复杂状态管理时使用useReducer的优势。通过实例展示了如何创建和使用Context,以及如何与子组件共享状态。同时,还探讨了useReducer的使用场景,包括处理复杂state逻辑和优化性能。最后,结合useReducer和useContext展示了如何在组件间共享和更新状态。
摘要由CSDN通过智能技术生成

一、useContetxt

react父组件传值给子组件,可以直接在组件上传值。如果有多个子组件或者还带有孙子组件,那么普通传值就会很繁琐,useContext能够实现组件状态的穿透

  1. 父组件创建一个 context 状态,我这里用 ts 给了个类型,没用到 ts 可以忽略
import { createContext, useState, useContext } from 'react';

type ContextType = {
  count: number
};
const ConfigContext = createContext({} as ContextType); 
  1. 创建俩内部的子组件和一个孙子组件,然后用创建的 ConfigContext 容器包裹
    ConfigContext.Provider 有个 value 属性就是你要传的值
    子组件使用 useContext 获取父组件传的值
// 孙子组件
const Son = () => {
  const { count } = useContext(ConfigContext); // 这里引入父组件的值
  return (
    <div>孙子组件: {count}</div>
  );
};
// 子组件
const Child = () => {
  const { count } = useContext(ConfigContext); // 这里引入父组件的值
  return (
    <div>
      子组件: {count}
      <Son />  // 孙子组件
    </div>
  );
};
const Second = () => {
  const { count } = useContext(ConfigContext);
  return (
    <div>子组件: {count}</div>
  );
};

// 父组件
const ContextDemo = () => {
  const [count, setCount] = useState<number>(0);
  return (
    <div>
      父组件:
      <ConfigContext.Provider value={{
        count: count
      }}>
        <Button onClick={() => setCount(count + 1)}>加1</Button>
        <Second />
        <Child />
      </ConfigContext.Provider>
    </div>
  );
};
  1. 外部创建的子组件使用父组件的值
    需要把父组件创建的 context 状态 export 出去
    然后子组件内引用
// 父组件内
export const ConfigContext = createContext({} as ContextType);  // export出去

// 外部子组件内
import { useContext } from 'react';
import { ConfigContext } from './index';

// 然后使用
const { count } = useContext(ConfigContext);

二、useReducer

在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数

  1. useReducer接受两个参数:reducer 和 state
    reduce 函数,有两个参数 state 状态和 action 触发类型和更新值
import {  useReducer } from 'react';
import { Button } from 'antd';

type StateType = {
  count: number,
  name: string,
  age: number
}
type ActionType = {
  type: 'add' | 'desc' | 'editName',
  payload?: any
}

// 状态
const states: StateType = {
  count: 1,
  name: '张三',
  age: 25
};

// 状态处理通知函数
const reducer: React.Reducer<StateType, ActionType> = (state, action) => {
  const { type, payload } = action;
  
  switch (type) {
    case 'add': 
      return { ...state, count: state.count + 1 };
    case 'desc': 
      return { ...state, count: state.count - 1 };
    case 'editName':
      return { ...state, name: payload};
  
    default:
      return state;
  }
};

const ReducerDemo = () => {

  const [ state, dispatch ] = useReducer(reducer, states);

  return (
    <div>
      <p>{ state.count }</p>
      <p>{ state.name }</p>
      <Button onClick={() => dispatch({ type: 'add' })}>加</Button>
      <Button onClick={() => dispatch({ type: 'desc' })}>减</Button>
      <Button onClick={() => dispatch({ type: 'editName', payload: '李四' })}>改名</Button>
      <Child />
    </div>
  );
};

export default ReducerDemo;
  1. state初始值需要计算或者需要引用其他值,不推荐 state = initialState

React 不使用 state = initialState 这一由 Redux 推广开来的参数约定。有时候初始值依赖于 props,因此需要在调用 Hook 时指定。如果你特别喜欢上述的参数约定,可以通过调用 useReducer(reducer, undefined, reducer) 来模拟 Redux 的行为,但我们不鼓励你这么做。

  • useReducer可以接受三个参数 reducer(reducer, initState, initFn),改版如下
// 状态
// const states: StateType = {
//   count: 1,
//   name: '大龙帅',
//   age: 25
// };
const initFn = (state: StateType): StateType => {
  state.name = '王二';
  return state;
};

 const initState: StateType = {
   count: 0,
   name: '张三',
   age: 25
 };
 const [ state, dispatch ] = useReducer(reducer, initState, initFn);

useContext搭配useReducer实现组件状态共享

import React, { useReducer, useContext, createContext } from 'react';
import { Button } from 'antd';

// useReducer
interface StateType {
  count: number
}
type ActionType = {
  type: 'add' | 'desc',
  payload?: any
}
const states: StateType = {
  count: 0
};
const reducer: React.Reducer<StateType, ActionType> = (state, action) => {
  const { type } = action;

  switch (type) {
    case 'add':
      return { ...state, count: state.count + 1 };
    case 'desc':
      return { ...state, count: state.count - 1 };
  
    default:
      return state;
  }
};

// useContext
type ContextType = {
  state: StateType,
  dispatch: React.Dispatch<ActionType>
}
const ConfigContext = createContext({} as ContextType);

// 子组件
const Child = () => {
  const { state, dispatch } = useContext(ConfigContext);

  return (
    <div style={{ marginTop: 20 }}>
      <p>子组件:{ state.count }</p>
      <Button onClick={() => dispatch({ type: 'add' })}>加</Button>
      <Button onClick={() => dispatch({ type: 'desc' })}>减</Button>
    </div>
  );
};

// 父组件
const Test = () => {
  
  const [state, dispatch] = useReducer(reducer, states);

  return (
    <div>
      <p>父组件: { state.count }</p>
      <Button onClick={() => dispatch({ type: 'add' })}>加</Button>
      <Button onClick={() => dispatch({ type: 'desc' })}>减</Button>

      <ConfigContext.Provider value={{
        state,
        dispatch
      }}>
        <Child />
      </ConfigContext.Provider>
    </div>
  );
};

export default Test;
useContextuseReducer都是React的Hook函数,用于处理状态管理和组件之间的数据传递。 1. useContext:用于在组件中获取和共享全局状态。它接收一个Context对象作为参数,并返回该Context的当前值。这个值是由最近的上层Context.Provider组件提供的。使用useContext可以避免使用props将状态传递到多个嵌套组件中。 例子: ```javascript const MyContext = React.createContext(); function ParentComponent() { const value = "Hello, useContext!"; return ( <MyContext.Provider value={value}> <ChildComponent /> </MyContext.Provider> ); } function ChildComponent() { const contextValue = React.useContext(MyContext); return <div>{contextValue}</div>; } ``` 2. useReducer:用于管理复杂的状态逻辑。它接收一个reducer函数和初始状态作为参数,并返回当前状态和dispatch函数。reducer函数接收当前状态和action作为参数,并根据action类型来更新状态。使用useReducer可以将状态和对状态的更新逻辑封装在一个函数中,使组件更加清晰和可维护。 例子: ```javascript function reducer(state, action) { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; default: throw new Error(); } } function Counter() { const [state, dispatch] = React.useReducer(reducer, { count: 0 }); return ( <div> Count: {state.count} <button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button> </div> ); } ``` 总结: - useContext用于获取全局状态,避免了props的传递,适用于简单的状态共享。 - useReducer用于管理复杂的状态逻辑,将状态和更新逻辑封装在一个函数中,适用于较为复杂的状态管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值