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
接受三个参数:
- reducer 函数:用于定义状态如何随着动作(action)变化的纯函数。
- 初始状态:用于设置状态的初始值。
- 可选的初始化函数:如果你的初始状态需要计算,可以传入这个函数。
返回值是一个数组,包含当前状态和一个 dispatch 函数,用于发送动作以更新状态。
reducer 函数
reducer 函数接受两个参数:
- 当前状态(state)
- 动作(action)
它必须返回一个新的状态对象。
3.基础用法:
(1)定义一个reducer函数(根据不同的action返回不同的新状态)
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函数和状态的初始值
const initialState = { count: 0 };
function Counter() {const [state, dispatch] = useReducer(reducer, initialState);...
}
(3)事件发生时,通过dispatch函数分派一个action对象(通知reducer要返回哪个新状态并渲染UI)
function Counter() {...dispatch({ type: 'increment' })
}
(4)分派action时传参
使用示例
下面是一个使用 useReducer
的简单计数器示例:
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
import { createContext, useContext } from "react"// 1. createContext方法创建一个上下文对象const MsgContext = createContext()
(2)在顶层组件(App)中通过 Ctx.Provider
组件提供数据
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
钩子函数获取消费数据
function B () {// 3. 在底层组件 通过useContext钩子函数使用数据const msg = useContext(MsgContext)return (<div>this is B compnent,{msg}</div>)
}
示例代码
// App -> A -> Bimport { 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
:
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 函数。
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 函数。
const StateContext = React.createContext();
(3)创建提供者组件
定义一个提供者组件,将状态和 dispatch 通过上下文传递给子组件。
function StateProvider({ children }) {const [state, dispatch] = useReducer(reducer, initialState);return (<StateContext.Provider value={{ state, dispatch }}>{children}</StateContext.Provider>);
}
(4)在子组件中使用上下文
在需要访问状态和 dispatch 的子组件中,使用 useContext
来获取这些值。
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
包裹在需要访问状态的组件树上。
const App = () => (<StateProvider><ChildComponent /></StateProvider>
);
通过这种方式,任何嵌套在 StateProvider
内的组件都可以访问和更新共享状态,使状态管理更加集中和高效。