教你如何理解useContext加上useReducer

一.首先我们要知道useContext和useReducer是什么?

useContext和useReducer都是react中的hook

useContext

1.useContext的定义和作用

它是用于函数组件消费它是一个全局上下文,用于处理跨层级组件通信问题,它避免了组件之间props层层传递的复杂性,它可以直接获取到context中的某个值而不用通过props传递。

2.useContext的使用

创建useContext

js 复制代码
const ThemeContext = creatContext('light');

使用Provider提供值

jsx 复制代码
<ThemeContext.Provider value={theme}>
    // 这里的Theme为自定义的value值
....// 中间为组件
<ThemeContext.Provider/>

在子组件使用useContext获取值

js 复制代码
const theme = useContext(ThemeContext)

以下为完整示例代码

jsx 复制代码
import React, { useContext, useReducer } from 'react';
// 1. 创建 Context
const ThemeContext = React.createContext();
// 2. 创建组件
function App() {
  const [theme, toggleTheme] = useReducer(
    (state) => (state === 'light' ? 'dark' : 'light'),
    'light'
  );
  return (
    // 3. 提供 Context 值
    <ThemeContext.Provider value={theme}>
      <button onClick={toggleTheme}>切换主题</button>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

// 中间组件(不需要传递 props)
function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

// 4. 使用 useContext 获取 Context 值
function ThemedButton() {
  const theme = useContext(ThemeContext);

  return (
    <button style={{ background: theme === 'dark' ? '#333' : '#eee', color: theme === 'dark' ? '#fff' : '#000' }}>
      当前主题:{theme}
    </button>
  );
}

export default App;

useReducer

1.useReducer的定义和作用

它为管理复杂的状态逻辑提供了一种替代useState的方法,它是一种响应式状态管理。

Reducer是一个纯函数纯函数既是1.相同的输入值会得到相同的输出值2.无副作用不会对外部产生影响如:不改变全局变量,不发送网络请求,不操作DOM等。Reducer它接受两个参数state(当前状态) 和 action(动作)并且返回一个新的状态
dispatch用于发送动作到Reducer中,你调用一个dispatch并传入一个动作对象,reducer会根据整个动作来更新状态

2.useReducer的用法

  1. 定义 Reducer 函数:根据应用的业务逻辑定义 reducer 函数。该函数接收当前状态和动作作为参数,并返回新的状态。
  2. 使用 useReducer Hook :在组件中使用 useReducer 来初始化状态和 reducer 函数。useReducer 返回当前状态和 dispatch 方法。
  3. 分发动作:通过调用 dispatch 方法并传入动作对象来触发状态更新。
jsx 复制代码
import React, { useReducer } from 'react';

// 定义 Reducer 函数
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() {
  // 初始化状态为 { count: 0 },并指定 reducer 函数
  const [state, dispatch] = useReducer(reducer, { count: 0 });

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

useContext和useReducer配合使用

什么时候使用useContext 1.当我们想多个层级组件共享状态或配置时 2.避免props一层层传递

什么时候使用useReducer 1.当组件的状态逻辑复杂时,例如涉及多个子值的状态,或者下一个状态依赖于前一个状态。 2.当下一个状态依赖于前一个状态时,使用 useReducer 可以避免一些潜在的副作用问题。

所以我们常常将useContext和useReducer一起使用

1. 创建 Context

首先,创建一个 React Context 来包裹你的应用状态和 dispatch 函数。

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

const AppContext = createContext();

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. 创建 Provider 组件

接下来,创建一个 Context Provider 组件,该组件内部使用 useReducer 来管理状态,并通过 value 属性向子组件暴露状态和 dispatch 方法。

jsx 复制代码
export const AppProvider = ({ children }) => {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {children}
    </AppContext.Provider>
  );
};
3. 在顶层组件中使用 Provider

确保在你的应用顶层组件中使用这个 Provider,以便所有子组件都可以访问到状态和 dispatch 方法。

jsx 复制代码
import React from 'react';
import ReactDOM from 'react-dom';
import { AppProvider } from './AppProvider'; // 假设文件名为 AppProvider.js
import App from './App'; // 你的主应用组件

ReactDOM.render(
  <AppProvider>
    <App />
  </AppProvider>,
  document.getElementById('root')
);
4. 使用 useContext 钩子在组件中消费状态

最后,在需要访问状态或触发状态更新的组件中,使用 useContext 钩子来获取当前状态和 dispatch 方法。

javascript 复制代码
javascript
深色版本
import React, { useContext } from 'react';
import { AppContext } from './AppProvider';

function Counter() {
  const { state, dispatch } = useContext(AppContext);

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

export default Counter;

总结

我们通过结合使用 useReduceruseContext,可以构建一个简单而有效的状态管理模式,适用于中小规模的应用。这种方法不仅简化了状态管理,也减少了不必要的代码复杂度。

相关推荐
AALoveTouch8 分钟前
大麦APP抢票揭秘
javascript
持久的棒棒君33 分钟前
启动electron桌面项目控制台输出中文时乱码解决
前端·javascript·electron
小离a_a1 小时前
使用原生css实现word目录样式,标题后面的...动态长度并始终在标题后方(生成点线)
前端·css
郭优秀的笔记2 小时前
抽奖程序web程序
前端·css·css3
布兰妮甜2 小时前
CSS Houdini 与 React 19 调度器:打造极致流畅的网页体验
前端·css·react.js·houdini
小小愿望2 小时前
ECharts 实战技巧:揭秘 X 轴末项标签 “莫名加粗” 之谜及破解之道
前端·echarts
小小愿望3 小时前
移动端浏览器中设置 100vh 却出现滚动条?
前端·javascript·css
fail_to_code3 小时前
请不要再只会回答宏任务和微任务了
前端
摸着石头过河的石头3 小时前
taro3.x-4.x路由拦截如何破?
前端·taro
lpfasd1233 小时前
开发Chrome/Edge插件基本流程
前端·chrome·edge