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 -> 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
:
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
内的组件都可以访问和更新共享状态,使状态管理更加集中和高效。