Posted in

使用 React Context API 的最佳实践_AI阅读总结 — 包阅AI

包阅导读总结

1. 关键词:React Context API、多主题切换、避免重新渲染、最佳实践、组件管理

2. 总结:本文介绍了 React Context API 的最佳实践,包括其适用场景、解决 props 穿透问题、实现多主题切换,创建多个 Context 及防止重新渲染的方法,最后总结其优点及在实际开发中的作用。

3. 主要内容:

– 什么是 React Context API 及何时使用

– 作为 React 库的一部分,用于组件间共享全局数据,避免繁琐的 props 传递。

– 适用于多个嵌套组件共享状态的场景,如主题设置等。

– 浅色和深色模式 UI 主题

– 对比了使用 Props 传递和 Context API 实现主题切换的方案。

– 指出 Props 传递的弊端和 Context API 的优势。

– 如何创建多个 React Contexts

– 解释创建一个大 Context 存储所有全局变量的弊端。

– 建议创建多个 Context 分别管理相关数据,提高性能。

– 如何防止 React Context 重新渲染问题

– 介绍首选方法为使用多个 Context。

– 提到拆分组件传递值及使用 React.useMemo 等缓解办法。

– 总结

– 总结学习内容,强调实践的作用。

思维导图:

文章地址:https://mp.weixin.qq.com/s/T2rhz67xCljDVynXlZHVlA

文章来源:mp.weixin.qq.com

作者:王树光

发布时间:2024/8/7 8:22

语言:中文

总字数:2789字

预计阅读时间:12分钟

评分:91分

标签:React,Context API,多主题切换,性能优化,状态管理


以下为原文内容

本内容来源于用户推荐转载,旨在分享知识与观点,如有侵权请联系删除 联系邮箱 media@ilingban.com

本文作者为 360 奇舞团前端开发工程师

本文将详细介绍如何使用 React 的 Context API 优雅地实现多主题切换,解决 props 穿透问题,并避免不必要的重新渲染。通过具体的示例代码,展示如何在浅色和深色模式之间切换,并探讨在实际项目中管理多个 Context 的最佳实践。

目录

  1. 什么是 React Context API,何时使用?

  2. 如何创建多个 React 上下文(以及为什么应该这样做)

  3. 如何防止 React Context 重新渲染问题

什么是 React Context API,何时使用?

React Context API 是 React 库的一部分,它允许在组件之间共享全局数据,而无需通过每层组件传递 props。Context API 非常适合需要在多个嵌套组件中共享状态的场景,例如管理全局主题设置、用户身份验证状态或应用配置等。使用 Context API,可以避免繁琐的 props 传递,提高代码的可读性和维护性。

以下内容将通过具体示例展示如何在 React 应用中使用 Context API 实现多主题切换,并探讨其最佳实践。

浅色和深色模式 UI 主题

React Context 的一个常见应用是管理浅色和深色模式的 UI 主题。许多 UI 组件,如按钮、标题、导航栏等,都需要根据当前主题显示不同的样式。通过使用 Context,可以在整个应用中方便地共享和切换主题,而不需要在每个组件中手动传递 props。下面我们对比一下两种解决方案:使用Props传递的方案和Context API 解决方案

使用 Props 传递的方案

最直接的方法是通过顶层组件创建一个主题变量,然后将其作为 props 传递给组件树中的所有子组件。然而,这种方法会导致“props 穿透”问题,即每个中间组件都需要传递这个 props,即使它们并不实际使用该值。这不仅使代码变得冗长和难以维护,还可能导致中间组件在不必要的时候重新渲染,从而影响性能。

functionApp(){
consttheme='dark';
return<Parenttheme={theme}/>;
}

functionParent({theme}){
return<Childtheme={theme}/>;
}

functionChild({theme}){
return<Switchtheme={theme}/>;
}

functionSwitch({theme}){
return<Switchstyle={{background:theme==='dark'?'#000':'#fff'}}>切换主题</Switch>;
}

在上述代码中,theme 属性被一层层传递到最底层的 Switch 组件。虽然这种方式能实现功能,但显然并不优雅。每个中间组件都需要接受和传递 theme 属性,即使它们并不使用这个值。这不仅增加了代码的复杂度,还导致了潜在的性能问题。

Context API 解决方案

我们可以通过使用 Context API 来解决 props 穿透 问题。

创建 Context

首先,我们需要引入createContext,配置所需的主题颜色,并使用light主题作为默认值:

//src/contexts/ThemeContext.js
import{createContext}from"react";
exportconstthemes={
light:{
background:"#fff",
text:"#000",
current:'light'
},
dark:{
background:"#000",
text:"#fff",
},
};
exportconstThemeContext=createContext(themes.light);
创建 Provider 组件

接下来,我们需要创建一个组件,通过 Context 的 Provider 来提供全局状态。这个组件通常会包含状态和操作方法,并将它们作为值传递给 Provider。例如,以下的 <Navbar /><Switch /> 组件将可以访问 theme 状态:

//src/App.js
importReact,{useState}from"react"
import{ThemeContext,themes}from"./contexts/ThemeContext"
importNavbarfrom"./components/Navbar"
importSwitchfrom"./components/Switch"

constApp=()=>{
const[theme,setTheme]=useState(themes.light)

consttoggleTheme=()=>{
setTheme(state=>(state===themes.light?themes.dark:themes.light))
}

return(
<divclassName="App">
<ThemeContext.Providervalue={theme}>
<Navbar/>
<SwitchchangeTheme={toggleTheme}/>
</ThemeContext.Provider>
</div>

)
}

exportdefaultApp

在上面的代码中,通过 ThemeContext.ProviderthemesetTheme 方法传递给其子组件。这样,在 SwitchNavbar 组件中可以使用 useContext 钩子访问 ThemeContext

使用 Context

SwitchNavbar 组件中,我们使用 useContext 钩子来获取当前主题,并根据主题动态更改样式:

//src/components/Switch.js

importReact,{useContext}from"react"
import{ThemeContext}from"../contexts/themeContext"

constSwitch=({changeTheme})=>{
consttheme=useContext(ThemeContext)

return(
<Switch
style={{backgroundColor:theme.background,color:theme.text}}
onClick={changeTheme}
>

切换主题:{theme.current}
</Switch>

)
}

exportdefaultSwitch

//src/components/Navbar.js
importReact,{useContext}from"react"
import{ThemeContext}from"../contexts/themeContext"

constNavbar=()=>{
consttheme=useContext(ThemeContext)

return(
<divstyle={{backgroundColor:theme.background}}>
<ulstyle={{display:"flex",gap:"20px"}}>
<listyle={{color:theme.text}}>首页</li>
<listyle={{color:theme.text}}>广场</li>
<listyle={{color:theme.text}}>我的</li>
</ul>
</div>

)
}

exportdefaultNavbar

通过这样设置,组件可以访问全局变量,每次更新上下文中的值时,组件都会重新渲染。

浅色模式:

image-20240804200934957

深色模式:

image-20240804201002336

如何创建多个 React Contexts

在上面的示例中,我们只创建了一个上下文,即 ThemeContext。但是,如果我们还有其他需要全局使用的数据,例如当前登录用户的信息 usernameage,该怎么办?我们可以创建一个大的Context来存储需要全局使用的所有变量:

<GlobalContext.Providervalue={{theme,username,age}}>
<SwitchchangeTheme={toggleTheme}/>
<Navbar/>
</GlobalContext.Provider>

但这并不是一个好的做法。因为每当 Context 的值更新时,使用该 Context 的所有组件都会重新渲染。这意味着,每当更新任何用户的变量信息时,所有只关心主题变化而不需要关心用户数据变化的组件也会被重新渲染。这可能会降低应用的性能,尤其是在具有大量复杂组件的应用中。

为了解决这个问题,我们可以创建多个 Context。例如,一个用于管理主题(ThemeContext),另一个用于管理用户数据(UserContext)。如下所示:

//src/contexts/UserContext.js
import{createContext}from"react";
exportconstUserContext=createContext({
username:"",
age:0,
});

//src/App.js
importReact,{useState}from"react";
import{ThemeContext,themes}from"./contexts/ThemeContext";
import{UserContext}from"./contexts/UserContext";
importNavbarfrom"./components/Navbar";
importSwitchfrom"./components/Switch";

constApp=()=>{
const[theme,setTheme]=useState(themes.light);
const[user,setUser]=useState({username:"mario",age:25});

consttoggleTheme=()=>{
setTheme(state=>(state===themes.light?themes.dark:themes.light));
};

return(
<divclassName="App">
<ThemeContext.Providervalue={theme}>
<UserContext.Providervalue={user}>
<Navbar/>
<SwitchchangeTheme={toggleTheme}/>
</UserContext.Provider>
</ThemeContext.Provider>
</div>

);
};

exportdefaultApp;

通过这种方式,每个 context 中只存储与其相关的数据,这有助于防止不必要的组件重新渲染,从而提高应用程序的性能。

如何防止 React Context 重新渲染问题

正如上面所写的,每当更新Context值时,所有使用该上下文的组件都将被重新渲染——即使包装在 React.memo() 中也是如此。但我们可以通过以下方法缓解这个问题:

1. 使用多个 React Context

这是防止不必要重新渲染的首选方法。通过创建多个 context,将相关的数据分开存储,只有使用特定 context 的组件会因更新而重新渲染。

2. 拆分组件并传递所需的值

通过将组件拆分,并将所需的值作为 props 从 context 中传递,并将子组件包装在 React.memo 中。React.memo 是一个高阶组件(HOC),用于优化函数组件,通过缓存组件防止不必要的重新渲染。只有当其 props 发生变化时,组件才会重新渲染。

constCard=()=>{
constappContextValue=useContext(AppContext);
consttheme=appContextValue.theme;

return(
<div>
<CardTitletheme={theme}/>
<CardDescriptiontheme={theme}/>
</div>

);
};

constCardTitle=React.memo(({theme})=>{
return<h2style={{color:theme.text}}>2024年巴黎奥运会</h2>;
});

constCardDescription=React.memo(({theme})=>{
return<pstyle={{color:theme.text}}>2024年巴黎奥运会是第33届夏季奥林匹克运动会</p>;
});

3. 使用 React.useMemo()

通过将组件包装在 useMemo 中,并将theme作为依赖项,只有当theme更改时才会触发回调函数重新渲染组件。

constCard=()=>{
constappContextValue=useContext(AppContext);
consttheme=appContextValue.theme;

returnuseMemo(
()=>(
<div>
<CardTitletheme={theme}/>
<CardDescriptiontheme={theme}/>
</div>

),
[theme]
);
};

constCardTitle=({theme})=>{
return<h2style={{color:theme.text}}>2024年巴黎奥运会</h2>;
};

constCardDescription=({theme})=>{
return<pstyle={{color:theme.text}}>2024年巴黎奥运会是第33届夏季奥林匹克运动会</p>;
};

通过这些方法,可以有效减少 React Context 造成的不必要重新渲染,提升应用的性能。

总结

通过本文的学习,我们了解了如何利用 React 的 Context API 高效地实现多主题切换。我们探讨了使用 Context 解决 props 穿透问题的方案,展示了在应用中创建和管理多个 Context 的方法,并提供了避免不必要重新渲染的优化技巧。这些实践不仅能提升代码的可维护性,还能显著改善用户体验。在实际开发中,灵活运用这些技术,将帮助我们构建更为出色的 React 应用。