React 中 createContext 和 useContext 的深度应用与优化实战

文章目录

一.前置知识

  1. createContext简介
    • createContext是 React 提供的一个用于创建上下文(Context)的函数。上下文是一种在组件树中共享数据的方式,它允许你将数据传递给多个组件,而不必通过组件树的每一层手动传递props。这在处理一些全局状态(如主题、用户认证信息等)时非常有用。
    • 当你调用createContext时,它会返回一个包含两个属性的对象:Provider和Consumer(在使用函数组件和useContext钩子时,Consumer的使用方式被简化了)。Provider是一个组件,用于提供数据给它的后代组件;Consumer是一个用于订阅Provider提供的数据的组件(在使用useContext时这个过程更简单)。
  2. useContext简介
    • useContext是一个 React 钩子,它用于在函数组件中订阅由createContext创建的上下文。通过useContext,函数组件可以轻松地访问到在组件树中上层Provider组件提供的数据,使得在组件树中共享数据变得更加方便和简洁。
    • 它接收一个上下文对象(由createContext创建的)作为参数,并返回该上下文的当前值。这样,组件就可以根据这个值来进行渲染或其他操作。

二.代码实现

目录结构

js 复制代码
|------ pages
|------------ ContentProVider
|--------------------- index.jsx
|--------------------- ContentProvider.jsx
|--------------------- one.jsx
|--------------------- two.jsx
|--------------------- three.jsx
|--------------------- four.jsx
|--------------------- five.jsx

1.创建ContentProvider组件

ContentProvider.jsx

封装 createContext,useContext使用

jsx 复制代码
// 引入 React 的 createContext 和 useContext 方法,以及 useState 钩子
import { createContext, useContext, useState } from 'react'

// 创建一个 EventContext 的上下文对象,初始值为空对象
const EventContext = createContext({})

/**
 * useEventContext 是一个自定义钩子,用于获取 EventContext 的当前值。
 */
export const useEventContext = () => useContext(EventContext)

/**
 * ContentProvider 是一个组件,用于提供 EventContext 的值。
 * 这个组件提供为了封装 EventContext 的值,并且可以在整个组件中共享。
 */
export const ContentProvider = ({ children }) => {
  const [count, setCount] = useState(0)
  const [data, setData] = useState('null')

  //  updateData 是一个函数,用于更新 data 状态变量的值为当前时间戳。
  const updateData = () => {
    setData(new Date().getTime())
  }

  return (
    // 使用 EventContext.Provider 组件提供 count、setCount、data 和 updateData 的值
    <EventContext.Provider
      value={{
        count,
        setCount,
        data,
        updateData
      }}
    >
      {children}
    </EventContext.Provider>
  )
}

2.使用封装的ContentProvider组件 + useEventContext钩子函数

顶层组件

jsx 复制代码
import { useEventContext, ContentProvider } from './ContentProvider'
import OnePage from './one'

/**
 * CreateContent 组件作为顶层组件使用
 * 使用 useEventContext 钩子函数来获取上下文数据和方法,在页面上显示和操作这些数据。
 */
const CreateContent = () => {
  // 使用 useEventContext 钩子函数获取上下文数据和方法
  const { count, setCount, data, updateData } = useEventContext()
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <div style={{ borderBottom: '1px solid black', marginBottom: 10, paddingBottom: 10 }}>
        {count}
        <h1>{count}</h1>
        <button onClick={() => setCount(count + 1)}>{count}</button>
      </div>

      <div onClick={() => updateData()}>更新数据</div>
      <div>{data}</div>
      <hr />
      <div style={{ marginLeft: 25 }}>
        <OnePage />
      </div>
    </div>
  )
}

/**
 * CreateContentPage 组件是一个 React 函数组件,用于创建内容页面。
 * 它使用 ContentProvider 组件来提供上下文,并在其内部渲染 CreateContent 组件。
 *
 * @returns {JSX.Element} 返回一个包含 CreateContent 组件的 JSX 元素。
 */
const CreateContentPage = () => {
  // 使用 ContentProvider 组件来提供上下文
  return (
    <ContentProvider>
      <CreateContent />
    </ContentProvider>
  )
}

export default CreateContentPage

3.嵌套层级的函数组件 (这部分意义不大,只是为了展示嵌套层级)

jsx 复制代码
// one.jsx
import TwoPage from './two'
/**
 * OnePage 组件用来嵌套组件,用于展示第一层子组件。
 * 展示一个标题和一个嵌套的 TwoPage 组件。
 */
const OnePage = () => {
  return (
    <div>
      <h1>第一层子组件</h1>
      <div style={{ marginLeft: 25 }}>
        {/* 渲染 TwoPage 组件 */}
        <TwoPage />
      </div>
    </div>
  )
}

export default OnePage
jsx 复制代码
// two.jsx
import ThreePage from './three'
const TwoPage = () => {
  return (
    <div>
      <h1>第二层子组件</h1>
      <div style={{ marginLeft: 25 }}>
        <ThreePage />
      </div>
    </div>
  )
}

export default TwoPage
jsx 复制代码
// three.jsx
import FourPage from './four'
const ThreePage = () => {
  return (
    <div>
      <h1>第三层子组件</h1>
      <div style={{ marginLeft: 25 }}>
        <FourPage />
      </div>
    </div>
  )
}

export default ThreePage
jsx 复制代码
import FivePage from './five'

const FourPage = () => {
  return (
    <div>
      <h1>第四层子组件</h1>
      <div style={{ marginLeft: 25 }}>
        <FivePage />
      </div>
    </div>
  )
}
export default FourPage

4.最底层的函数组件

jsx 复制代码
// 导入 useEventContext 钩子
import { useEventContext } from './ContentProvider'

/**
 * FivePage 组件是最底部组件,用于展示和更新上下文数据。
 * 使用 useEventContext 钩子来获取上下文数据,并在页面上展示和更新这些数据。
 *
 */
const FivePage = () => {
  // 使用 useEventContext 钩子获取上下文数据
  const { count, setCount, data } = useEventContext()
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      <div style={{ borderBottom: '1px solid black', marginBottom: 10, paddingBottom: 10 }}>
        {count}
        <h1>{count}</h1>
        {/* 点击按钮增加 count 的值 */}
        <button onClick={() => setCount(count + 1)}>{count}</button>
      </div>

      <div>{data}</div>
      <hr />
    </div>
  )
}

export default FivePage

三.效果展示



四.总结

通过对 React 中 createContext 和 useContext 的深入学习和实践,我们能够有效地在组件树中共享数据,避免了繁琐的 props 层层传递。在实际应用中,合理地使用上下文可以提高代码的可维护性和可读性,尤其是在处理全局状态或需要在多个组件间共享的数据时。同时,通过对代码的优化,我们进一步提升了性能和代码质量,使得应用在运行时更加高效和稳定。

相关推荐
卸任3 小时前
Vibe coding工具使用心得
前端·ai编程
brien94 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance4 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M4 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写4 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李4 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易4 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding4 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马4 小时前
前沿视界
前端
kyriewen5 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员