React Context 新手指南(2021)


prtyaa
prtyaa 2023-12-26 17:50:08 66515
分类专栏: 资讯
  • React context 是每个 React 开发工程师都应该知道的重要工具。它可以让你在应用程序中轻松地共享数据。

    在这份全面的指南中,我们将介绍什么是 React context,如何使用它,何时以及何时不使用context,等等。

    即使你以前从未使用过 React context,你也来对地方了。通过本文简单和循序渐进的例子你将学习到所需的一切知识。

    我们开始吧!

    什么是 React context?

    React context 让我们可以无需使用 props 即可在 React 应用的任意组件中传递和使用数据。

    换句话说,React context 让我们在组件中分享数据更加方便。

    何时该用 React context?

    当你传递可以在应用程序的任何组件中使用的数据时,React context 非常有用。

    这类数据包括:

    • 主题数据(如深色或浅色模式)
    • 用户数据(当前经过身份验证的用户)
    • 和位置相关的数据(如用户语言或地区)

    数据应该放在不需要经常更新的 React context 中。

    为什么呢?因为 context 不是作为一个完整的状态管理系统而设计的。它的设计初衷是让使用数据更加容易。

    你可以把 React context 看作为 React 组件设计的类似全局变量的东西。

    React context 解决了什么问题?

    React context 帮我们避免了属性下钻(props drilling)的问题。

    属性下钻(props drilling)是一个术语,是指把属性穿透多层不需要这些属性的组件而传递到深层内嵌的组件。

    这里有一个属性下钻的例子。在这个应用中,我们可以访问主题数据,我们希望将这些数据作为属性传递给应用的所有组件。

    然而,正如你所看到的,App 的直接子级组件,如 Header,也必须使用属性向下传递主题数据。

    export default function App({ theme }) {
      return (
        <>
          <Header theme={theme} />
          <Main theme={theme} />
          <Sidebar theme={theme} />
          <Footer theme={theme} />
        </>
      );
    }
    
    function Header({ theme }) {
      return (
        <>
          <User theme={theme} />
          <Login theme={theme} />
          <Menu theme={theme} />
        </>
      );
    }
    

    这个例子有什么问题?

    问题是,我们正在下钻多个不需要此属性的组件来传递 theme 属性。

    Header 组件不需要 theme,只需要将其传递给它的子组件。换句话说,User、Login 和 Menu 直接使用 theme 数据会更好一些。

    这就是 React context 的好处 —— 我们可以完全绕过使用属性,因此避免了属性下钻的问题。

    如何使用 React context?

    Context 是 React 内置的一个 API,从 React 16 可用。

    这意味着我们可以在任何 React 项目中导入 React 来直接创建和使用 context 。

    使用 React context 有四个步骤:

    • 使用 createContext 方法创建 context。
    • 获取创建的 context,然后把组件树包在 context provider 里。
    • 使用 value 属性把你想要的值放在 context provider 上。
    • 在任意组件中使用 context consumer 读取你设置的值。

    听起来有点绕?实际上比你想象的要简单。

    让我们看一个非常简单的例子。在我们的应用中,我们使用 context 向下传递姓名,然后在嵌套组件 User 中读取它。

    import React from 'react';
    
    export const UserContext = React.createContext();
    
    export default function App() {
      return (
        <UserContext.Provider value="Reed">
          <User />
        </UserContext.Provider>
      )
    }
    
    function User() {
      return (
        <UserContext.Consumer>
          {value => <h1>{value}</h1>} 
          {/* prints: Reed */}
        </UserContext.Consumer>
      )
    }
    

    让我们逐步分解上面的步骤:

    1. 在 App 组件中,我们用 React.createContext() 创建了 context 并保存其结果到一个名为 UserContext 的变量里。一般来说,你需要像上面这样把它导出,因为组件是保存在另外的文件中的。注意我们在调用 React.createContext() 时可以传一个初始值作为 value 属性。
    2. 在 App 组件中,我们用到了 UserContext。准确来说是 UserContext.Provider。创建的 context 有两个属性:Provider 和 Consumer,二者均为组件。为了把数据传递到应用的每个组件里,我们用 Provider 组件把组件(对于这个例子来说是 User)包裹起来。
    3. 在 UserContext.Provider 上,我们写上想要在整个组件树中传递的数值。把数值赋值到 value 属性上。对于本例来说是姓名(即 Reed)。
    4. 在 User 或者其他组件中想要使用在 context 中提供的值,使用 consumer 组件:UserContext.Consumer。要使用向下传递的值,我们用到了所谓的渲染属性模式(render props pattern)。它就是一个函数,在这个函数里 consumer 组件会把该值作为一个属性提供给我们。在这个函数内部,我们就可以使用它了。

    什么是 useContext hook?

    看过了上面的例子,你可能觉得渲染属性模式有点怪异。

    另外一种使用 context 的方式自 React 16.8 随着 React hooks 出现了。现在我们可以用 useContext hook 使用 context 了。

    我们可以在组件的顶部将整个 context 对象传递给 React.useContext() ,而不再使用渲染属性。

    上面的例子用 useContext hook 改写后如下:

    import React from 'react';
    
    export const UserContext = React.createContext();
    
    export default function App() {
      return (
        <UserContext.Provider value="Reed">
          <User />
        </UserContext.Provider>
      )
    }
    
    function User() {
      const value = React.useContext(UserContext);  
        
      return <h1>{value}</h1>;
    }
    

    useContext 的优点是让我们的组件更加简洁,而且可以创建自定义 hooks。

    你可以直接用 consumer 组件,也可以用 useContext hook,取决于你的偏好。

    你可能无需 context

    许多工程师犯的错误是,一旦他们不得不将 props 向下传递几层到某个组件时,就转用 context。

    这是一个应用,它内嵌的 Avatar 组件从 App 组件接收两个属性 username 和 avatarSrc。

    export default function App({ user }) {
      const { username, avatarSrc } = user;
    
      return (
        <main>
          <Navbar username={username} avatarSrc={avatarSrc} />
        </main>
      );
    }
    
    function Navbar({ username, avatarSrc }) {
      return (
        <nav>
          <Avatar username={username} avatarSrc={avatarSrc} />
        </nav>
      );
    }
    
    function Avatar({ username, avatarSrc }) {
      return <img src={avatarSrc} alt={username} />;
    }
    

    如果可以的话,我们希望避免通过组建传值时传递不需要用到的多个属性。

    我们可以怎么做?

    我们应该更好地组织我们的组件,而不是因为属性下钻就立即使用 context。

    由于只有最顶层的组件 App 需要感知到 Avatar 组件,我们可以直接在 App 组件内创建它。

    这样做我们就可以只向下传递一个属性 avatar,而不是两个属性。

    export default function App({ user }) {
      const { username, avatarSrc } = user;
    
      const avatar = <img src={avatarSrc} alt={username} />;
    
      return (
        <main>
          <Navbar avatar={avatar} />
        </main>
      );
    }
    
    function Navbar({ avatar }) {
      return <nav>{avatar}</nav>;
    }
    

    简言之:不要马上借助于 context。看看能否优化组件来避免属性下钻。

    React context 可以替代 Redux 吗?

    这个问题要分两面来看。

    对于许多 React 新手来说,Redux 是一种更加容易传递数据的方式。这是因为 Redux 自身内部使用了 React context。

    不过,如果你不需要更新状态(state),只是在组件树中向下传递数据,那么无需像 Redux 这类全局状态管理库。

    结语

    希望本文能让你更好地理解如何使用React context。

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=30940
赞同 0
评论 0 条
prtyaaL1
粉丝 1 发表 2554 + 关注 私信
上周热门
银河麒麟添加网络打印机时,出现“client-error-not-possible”错误提示  1507
银河麒麟打印带有图像的文档时出错  1426
银河麒麟添加打印机时,出现“server-error-internal-error”  1217
统信操作系统各版本介绍  1137
统信桌面专业版【如何查询系统安装时间】  1134
统信桌面专业版【全盘安装UOS系统】介绍  1090
麒麟系统也能完整体验微信啦!  1046
统信【启动盘制作工具】使用介绍  698
统信桌面专业版【一个U盘做多个系统启动盘】的方法  639
信刻全自动档案蓝光光盘检测一体机  545
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

添加我为好友,拉您入交流群!

请使用微信扫一扫!