useContext
useContext是React的一个Hook,用于在函数组件中访问上下文(context)的值。它可以帮助我们在组件树中共享状态,而不需要通过props一层层传递
特点
- 用于跨组件共享状态
- 需要配合React.createContext和Context.Provider使用
- 简化了组件间的状态传递
基本用法
- 创建 Context
import React, { createContext, useContext } from 'react';
const MyContext = createContext('默认值');
- 提供 Context值
const App = () => {
return (
// 这个value可以传递任何类型的数据,包括字符串、数组、对象、函数等
<MyContext.Provider value="共享值">
<Child />
</MyContext.Provider>
)
}
- 消费 Context值
const Child = () => {
const value = useContext(MyContext)
return <div>{value}</div>
}
注意事项
- useContext只能在函数组件或自定义Hook中使用,不能在类组件中使用
- 如果Context.Provider的value发生变化,所有使用该Context的组件都会重新渲染
- 如果没有Provider包裹,useContext会返回createContext时定义的默认值
- 性能优化:如果value传递的是一个对象或数组,避免在每次渲染时创建新的引用(例如直接传递字面量对象或数组时),可以使用useMemo缓存value
const value = useMemo(() => ({name: 'John',age:30}), [])
- 嵌套Context:如果需要传递多个值,可以将他们组合成一个对象,或者使用多个Context.
使用场景
- 主题切换:在应用中实现亮色和暗色主题的切换
- 用户认证:共享当前用户的认证状态,例如是否已登录
- 多语言支持:根据用户的语言偏好动态切换界面语言
- 全局状态管理:在小型应用中替代Redux等状态管理工具,简化状态共享
useReducer
useReducer是React的一个的Hook。用于在函数组件中进行更复杂的状态管理。它适合于状态逻辑较复杂、涉及多个子值或下一个状态依赖于之前状态的场景。用法类似于Redux的reducer
基本用法
import { useReducer } from 'react'
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] = useReducer(reducer, {count: 0})
return (
<>
Count: {state.count}
// 通过dispatch 触发action 的函数
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
)
}
1、render函数根据action.type来决定如何更新状态
2、dispatch函数用于触发状态更新,每次点击按钮时,都会调用dispatch并传递相应的action对象
使用场景
- 复杂的状态逻辑:当状态更新逻辑较为复杂,或者需要根据前一个状态来计算新状态时,useReducer可以更好地组织代码
- 多个子值:当状态是一个包含多个子值的对象时,useReducer可以更方便管理这些子值
- 性能优化:在某些情况下,useReducer可以比useState更高效,因为它允许将状态更新逻辑集中在一个地方,减少不必要的重复渲染
useContext和useReducer结合使用实现全局状态管理(类似于Redux)
- useReducer管理全局状态
- useContext提供和消费这个状态
import React, { createContext, useReducer, useContext } from 'react'
const CountContext = createContext(null)
function reducer(state, action){
switch(action.type){
case 'add':
return { count: state.count + 1 }
default:
return state
}
}
function ConterProvider({ children }){
const [state, dispatch] = useReducer(reducer, {count: 0})
return (
<CountContext.Provider value={{state, dispatch}}>
{ children }
</CountContext.Provider>
)
}
function Counter(){
const { state, dispatch } = useContext(CountContext)
return (
<button onClick={() => dispatch({ type: 'add' })}>
Count: {state.count}
</button>
)
}
// 使用
function App() {
return (
<CounterProvider>
<Counter />
</CounterProvider>
)
}