包阅导读总结
1.
关键词:React Context API、多主题切换、props 穿透、重新渲染、最佳实践
2.
总结:本文介绍了 React Context API 的使用,包括解决多主题切换和 props 穿透问题,创建多个 Context 的方法,以及防止重新渲染的技巧,强调了其在提升代码可维护性和用户体验方面的作用。
3.
主要内容:
– React Context API 简介
– 作用:在组件间共享全局数据,避免 props 传递
– 适用场景:管理全局主题、用户认证状态、应用配置等
– 浅色和深色模式 UI 主题切换
– Props 传递方案的问题:导致 props 穿透和不必要的重新渲染
– Context API 解决方案
– 创建 Context
– 创建 Provider 组件
– 使用 Context 动态更改样式
– 如何创建多个 React Contexts
– 避免将所有全局变量放在一个大的 Context 中
– 应创建多个 Context 分别管理相关数据,防止不必要的重新渲染
– 如何防止 React Context 重新渲染问题
– 使用多个 React Context
– 拆分组件并传递所需值,使用 React.memo 优化
– 使用 React.useMemo 并设置依赖项
– 总结
– 强调 Context API 实践在提升代码和用户体验方面的价值
思维导图:
文章地址: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 的最佳实践。
目录
-
什么是 React Context API,何时使用?
-
如何创建多个 React 上下文(以及为什么应该这样做)
-
如何防止 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.Provider
将 theme
和 setTheme
方法传递给其子组件。这样,在 Switch
和 Navbar
组件中可以使用 useContext
钩子访问 ThemeContext
。
使用 Context
在 Switch
和 Navbar
组件中,我们使用 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
通过这样设置,组件可以访问全局变量,每次更新上下文中的值时,组件都会重新渲染。
浅色模式:
深色模式:
如何创建多个 React Contexts
在上面的示例中,我们只创建了一个上下文,即 ThemeContext
。但是,如果我们还有其他需要全局使用的数据,例如当前登录用户的信息 username
和 age
,该怎么办?我们可以创建一个大的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 应用。