React中useContext,useReducer简单实现全局状态管理

useContext

Context Hook 是可以让子组件给后代组件共享数据

接受一个上下文对象(从' React.createContext '返回的值)并返回当前 context 值,该值由最近的给定上下文提供程序提供。

useReducer

useReducer 是 useState 的另一种选择,当我们要实现的状态逻辑较为复杂时,useReducer 优先级更高,还可以优化触发深度更新组件的性能,因为 useReduce 可以向下出传递 dispatch 而不是回调

useReducer 支持我们传递三个参数, 第一个参数是 reducer 纯函数 第二个参数是我们要使用的初始化值 第三个参数是一个函数,它支持我们对 useReducer 进行初始化操作

实操

定义reducer函数

我们可以先通过useReducer来实现主题或者一些其他状态的收集以及修改,基本代码如下:

typescript 复制代码
export type State={
  theme:'dark' | 'light'
}
export enum ActionType{
  UPDATE="UPDATE",
}
type UpdateAction={
  type: ActionType
  field: string
  value: any
}

export type Action = UpdateAction

const initStateStorage = JSON.parse(localStorage.getItem('mySiteState') || '{}')

const initData: State={
  theme:'dark',
  ...initStateStorage
}
export function reducer(state: State, action: Action) {
  switch (action.type) {
    case ActionType.UPDATE:
      localStorage.setItem('mySiteState', JSON.stringify({ ...state, [action.field]: action.value }))
      return { ...state, [action.field]: action.value }
    default:
      throw new Error()
  }
}

上方代码中抽离出来了一个reducer函数来改变全局状态的值,并定义了一个初始化的状态,之后可以通过判断动作来进行状态的更新,并将状态储存到localStorage中实现持久化

定义上下文

接下来需要定义一个全局容器来提供状态,具体代码如下:

tsx 复制代码
import { Dispatch, ReactNode, createContext, useContext, useMemo, useReducer } from "react"
import { Action, State, initState, reducer } from "./reducers/AppReducer"

type AppContextProps = {
  state: State
  dispatch: Dispatch<Action>
}

const AppContext=createContext(null!)

export function useAppContext(){
  return useContext(AppContext)
}

export default function AppContextProvider({ children }: { children: ReactNode }) {
  const [state, dispatch] = useReducer(reducer, initState)
  // 把创建函数和依赖数组项作为参数传入 useMemo,它仅仅会在数组依赖项中的值改变时才会重新计算值
  const contextValue = useMemo(() => {
    return { state, dispatch }
  }, [state, dispatch])
  return <AppContext.Provider value={contextValue}>{children}</AppContext.Provider>
}

使用

在main.ts或是其他位置对App组件进行包裹,实现全局状态的使用

typescript 复制代码
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import AppContextProvider, { useAppContext } from './AppContext.tsx'

const Container = () => {
  const { state: { theme } } = useAppContext()
  return (
      <div style={{
        backgroundColor: theme === 'dark' ? 'black' : 'white',
        width: '100vw',
        height: '100vh'
      }}>
        <App />
      </div>
  )
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <AppContextProvider>
      <Container />
    </AppContextProvider>
  </React.StrictMode>,
)

全局状态修改

tsx 复制代码
import { useAppContext } from './AppContext'
import { ActionType } from './reducers/AppReducer'
function App() {
  const { state: { loading, theme }, dispatch } = useAppContext()
  const changeTheme = () => {
    if (theme === 'dark') {
      dispatch({
        type: ActionType.UPDATE,
        field: 'theme',
        value: 'light'
      })
    } else {
      dispatch({
        type: ActionType.UPDATE,
        field: 'theme',
        value: 'dark'
      })
    }
  }
  return (
      <button onClick={async () => changeTheme()}>
        changeTheme
      </button>
  )
}

export default App
相关推荐
_丿丨丨_5 小时前
XSS(跨站脚本攻击)
前端·网络·xss
天天进步20155 小时前
前端安全指南:防御XSS与CSRF攻击
前端·安全·xss
拾光拾趣录7 小时前
括号生成算法
前端·算法
拾光拾趣录8 小时前
requestIdleCallback:让你的网页如丝般顺滑
前端·性能优化
前端 贾公子8 小时前
vue-cli 模式下安装 uni-ui
前端·javascript·windows
拾光拾趣录8 小时前
链表合并:双指针与递归
前端·javascript·算法
@大迁世界8 小时前
前端:优秀架构的坟墓
前端·架构
期待のcode8 小时前
图片上传实现
java·前端·javascript·数据库·servlet·交互
hbrown9 小时前
Flask+LayUI开发手记(十一):选项集合的数据库扩展类
前端·数据库·python·layui
猫头虎9 小时前
什么是 npm、Yarn、pnpm? 有什么区别? 分别适应什么场景?
前端·python·scrapy·arcgis·npm·beautifulsoup·pip