React中常用的hook函数(三)——useReducer和useContext

React中常用的hook函数(一)------useState和useEffect_usestate useeffect-CSDN博客https://blog.csdn.net/Mrs_Lupin/article/details/142905749?sharetype=blogdetail&sharerId=142905749&sharerefer=PC&sharesource=Mrs_Lupin&spm=1011.2480.3001.8118React中常用的hook函数(二)------useMemo和useCallback-CSDN博客https://blog.csdn.net/Mrs_Lupin/article/details/143424548?sharetype=blogdetail&sharerId=143424548&sharerefer=PC&sharesource=Mrs_Lupin&spm=1011.2480.3001.8118

一、useReducer

1.作用:

用于管理组件状态,尤其在状态逻辑较复杂 或者状态依赖于之前状态 时特别有用。它通常用于代替 useState

2.语法:

useReducer函数

useReducer 接受三个参数:

  1. reducer 函数:用于定义状态如何随着动作(action)变化的纯函数。
  2. 初始状态:用于设置状态的初始值。
  3. 可选的初始化函数:如果你的初始状态需要计算,可以传入这个函数。

返回值是一个数组,包含当前状态和一个 dispatch 函数,用于发送动作以更新状态。

reducer 函数

reducer 函数接受两个参数:

  1. 当前状态(state)
  2. 动作(action)

它必须返回一个新的状态对象。

3.基础用法:

(1)定义一个reducer函数(根据不同的action返回不同的新状态)

javascript 复制代码
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return { count: state.count };
  }
}

(2)在组件中调用useReducer,并传入reducer函数和状态的初始值

javascript 复制代码
const initialState = { count: 0 };
function Counter() {
    const [state, dispatch] = useReducer(reducer, initialState);
    ...
}

(3)事件发生时,通过dispatch函数分派一个action对象(通知reducer要返回哪个新状态并渲染UI)

javascript 复制代码
function Counter() {
    ...
    dispatch({ type: 'increment' })
}

(4)分派action时传参

使用示例

下面是一个使用 useReducer 的简单计数器示例:

javascript 复制代码
import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    case 'update':
      return { count: action.payload };
    default:
      return { count: state.count };
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'update', payload: 100 })}>to 100</button>
    </>
  );
}

export default Counter;

4.为什么要使用useReducer

  • 状态逻辑复杂:当状态逻辑涉及多个子值或者状态依赖于之前的状态时,使用useReducer可以更好地组织代码。useState适用于管理简单状态,如布尔值、数字、字符串等,或者只有几个状态值需要管理。
  • 可读性:使用 reducer 函数可以使状态更新的逻辑更加集中,便于理解和维护。
  • 调试:可以更容易地跟踪状态变化,特别是在大型应用中。

二、useContext

1.作用

在函数组件中访问 React 上下文(Context),可以在组件树中跨层级传递数据(通信)

2.实现步骤

(1)使用 createContext方法创建一个上下文对象Ctx

javascript 复制代码
import { createContext, useContext } from "react"

// 1. createContext方法创建一个上下文对象

const MsgContext = createContext()

(2)在顶层组件(App)中通过 Ctx.Provider 组件提供数据

javascript 复制代码
function App () {
  const msg = 'this is app msg'
  return (
    <div>
      {/* 2. 在顶层组件 通过Provider组件提供数据 */}
      <MsgContext.Provider value={msg}>
        this is App
        <A />
      </MsgContext.Provider>
    </div>
  )
}

(3)在底层组件(B)中通过 useContext 钩子函数获取消费数据

javascript 复制代码
function B () {
  // 3. 在底层组件 通过useContext钩子函数使用数据
  const msg = useContext(MsgContext)
  return (
    <div>
      this is B compnent,{msg}
    </div>
  )
}

示例代码

javascript 复制代码
// App -> A -> B

import { createContext, useContext } from "react"

// 1. createContext方法创建一个上下文对象

const MsgContext = createContext()

function A () {
  return (
    <div>
      this is A component
      <B />
    </div>
  )
}

function B () {
  // 3. 在底层组件 通过useContext钩子函数使用数据
  const msg = useContext(MsgContext)
  return (
    <div>
      this is B compnent,{msg}
    </div>
  )
}

function App () {
  const msg = 'this is app msg'
  return (
    <div>
      {/* 2. 在顶层组件 通过Provider组件提供数据 */}
      <MsgContext.Provider value={msg}>
        this is App
        <A />
      </MsgContext.Provider>
    </div>
  )
}

export default App

3. 多重上下文

如果需要使用多个上下文,可以多次调用 useContext

javascript 复制代码
import React, { createContext, useContext, useState } from 'react';

// 创建主题上下文
const ThemeContext = createContext();
// 创建用户上下文
const UserContext = createContext();

const App = () => {
  const [theme, setTheme] = useState('light');
  const [user, setUser] = useState({ name: 'John Doe' });

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <UserContext.Provider value={{ user, setUser }}>
        <UserProfile />
      </UserContext.Provider>
    </ThemeContext.Provider>
  );
};

const UserProfile = () => {
  //在底层组件中获取数据
  const { theme, setTheme } = useContext(ThemeContext);
  const { user } = useContext(UserContext);

  return (
    <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}>
      <h1>{user.name}</h1>
      <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle Theme
      </button>
    </div>
  );
};

4. 注意事项

  • 性能考虑 :当 Provider 的 value 改变时,所有使用该上下文的组件会重新渲染,因此可以通过缓存(如 useMemo)来优化性能。
  • 作用域:上下文的值是从最近的 Provider 组件中获取的,所以要确保 Provider 包裹住需要使用该上下文的组件。

5.结合useReducer

useReducer 也常与 useContext 结合使用,以便在组件树中共享状态:

使用步骤

(1)使用 useReducer 管理状态

useReducer 是一个 React Hook,适用于管理复杂的状态逻辑。它接收一个 reducer 函数和初始状态,并返回当前状态和一个 dispatch 函数。

javascript 复制代码
const initialState = { count: 0 };

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();
  }
}
(2)创建上下文

通过 createContext 创建一个上下文,来共享状态和 dispatch 函数。

javascript 复制代码
const StateContext = React.createContext();
(3)创建提供者组件

定义一个提供者组件,将状态和 dispatch 通过上下文传递给子组件。

javascript 复制代码
function StateProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <StateContext.Provider value={{ state, dispatch }}>
      {children}
    </StateContext.Provider>
  );
}
(4)在子组件中使用上下文

在需要访问状态和 dispatch 的子组件中,使用 useContext 来获取这些值。

javascript 复制代码
const ChildComponent = () => {
  const { state, dispatch } = useContext(StateContext);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
    </div>
  );
};
(5)组合使用

在应用的根组件中,将 StateProvider 包裹在需要访问状态的组件树上。

javascript 复制代码
const App = () => (
  <StateProvider>
    <ChildComponent />
  </StateProvider>
);

通过这种方式,任何嵌套在 StateProvider 内的组件都可以访问和更新共享状态,使状态管理更加集中和高效。

相关推荐
木子七21 分钟前
Js Dom
前端·javascript
重生之我是菜鸡程序员28 分钟前
uniapp 使用vue/pwa
javascript·vue.js·uni-app
谢小飞1 小时前
我做了三把椅子原来纹理这样加载切换
前端·three.js
圈圈的熊1 小时前
HTTP 和 HTTPS 的区别
前端·网络协议·http·https
GIS程序媛—椰子1 小时前
【Vue 全家桶】2、Vue 组件化编程
前端·javascript·vue.js
Beamon__1 小时前
element-plus按需引入报错IconsResolver is not a function
前端
努力奔波的程序猿1 小时前
HBuilderx修改主题色-改变编辑器背景颜色等
前端
正小安1 小时前
Vue 3 性能提升与 Vue 2 的比较 - 2024最新版前端秋招面试短期突击面试题【100道】
前端·vue.js·面试
yqcoder1 小时前
electron 中 ipcRenderer 的常用方法有哪些?
前端·javascript·electron