在React中,useContext 是一种非常方便的全局状态管理工具,它可以让我们在组件之间共享状态,而不需要通过层层传递 props。然而,当我们在一个大型的 React 应用中过度使用 useContext 时,可能会遇到性能问题。这是因为当一个 context 的值改变时,所有使用这个 context 的组件都会重新渲染,即使这个组件并不需要那个改变的值。

示例

举个例子,假设我们有一个全局的用户 context,它包含了用户的详细信息和一些设置:

const UserContext = React.createContext();

function App() {
const [user, setUser] = useState({ name: 'John', age: 30, theme: 'dark' }); const handleChangeName = () => {
setUser({ ...user, name: 'AAA' });
};
return (
<UserContext.Provider value={user}>
<Profile />
<Settings />
<button onClick={handleChangeName}>Change Name</button>
</UserContext.Provider>
);
} function Profile() {
const user = useContext(UserContext); return <h1>Welcome, {user.name}!</h1>;
} function Settings() {
const user = useContext(UserContext); return <div>Your current theme is: {user.theme}</div>;
}

在这个例子中,Profile 和 Settings 组件都使用了 UserContext。如果用户的主题改变了,Profile 组件也会重新渲染,即使它并不需要知道主题的信息。

改进方法

一种改进方法是使用 React 的 useMemouseCallback钩子来避免不必要的重新渲染。我们可以为每一个需要共享的状态创建一个单独的 context,然后使用 useMemo useCallback 来确保只有当这个状态改变时,使用这个状态的组件才会重新渲染:

const NameContext = React.createContext();
const ThemeContext = React.createContext(); function App() {
console.log('App');
const [user, setUser] = useState({ name: 'John', age: 30, theme: 'dark' }); const userName = useMemo(() => user.name, [user.name]);
const userTheme = useMemo(() => user.theme, [user.theme]); const handleChangeName = useCallback(() => {
setUser({ ...user, name: 'AAA' });
}, [user]); return (
<>
<NameContext.Provider value={userName}>
<ThemeContext.Provider value={userTheme}>
<Profile />
<Settings />
<button onClick={handleChangeName}>Change Name</button>
</ThemeContext.Provider>
</NameContext.Provider>
</>
);
}
const Profile = React.memo(function Profile() {
console.log('Profile');
const name = useContext(NameContext); return <h1>Welcome, {name}!</h1>;
}); const Settings = React.memo(function Settings() {
console.log('Settings');
const theme = useContext(ThemeContext); return <h1>Your current theme is: {theme}</h1>;
});

这样,只有当相关的状态改变时,对应的组件才会重新渲染,从而提高了性能。

举例useContext性能低下的样例,同时推荐用什么方法改进的更多相关文章

  1. Qt 鼠标样式特效探索样例(一)——利用时间器调用QWidget.move()函数

    Qt 鼠标样式特效探索样例(一)       心血来潮,突然想在Qt里玩一把鼠标样式,想到在浏览网页时,经常看到漂亮的鼠标动画,于是今天摸索着乱写个粗糙的demo,来满足自己的好奇心. 效果图 方案要 ...

  2. C++的性能C#的产能?! - .Net Native 系列《三》:.NET Native部署测试方案及样例

    之前一文<c++的性能, c#的产能?!鱼和熊掌可以兼得,.NET NATIVE初窥> 获得很多朋友支持和鼓励,也更让我坚定做这项技术的推广者,希望能让更多的朋友了解这项技术,于是先从官方 ...

  3. 【Scala篇】--Scala中Trait、模式匹配、样例类、Actor模型

    一.前述 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大. 模式匹配机制相当于java中的switch-case. 使用了case关键字的类定义就是样例类(case ...

  4. JPA入门样例(採用JPA的hibernate实现版本号)

    (1).JPA介绍: JPA全称为Java Persistence API ,Java持久化API是Sun公司在Java EE 5规范中提出的Java持久化接口.JPA吸取了眼下Java持久化技术的长 ...

  5. RESTful设计原则和样例(开发前后台接口)

    摘要 REST(表征性状态传输)设计风格;REST通常基于使用HTTP,URI协议和标准.使用URL标识资源,开发前后台接口.主要使用post,get方式 参考博文: http://www.cnblo ...

  6. CloudSim样例分析

    自带八个样例描述: cloudsim-2.1.1\examples目录下提供了一些CloudSim样例程序,每个样例模拟的环境如下: (1)CloudSimExample1.Java:创建一个一台主机 ...

  7. Ajax框架,DWR介绍,应用,样例

    使用Ajax框架 1. 简化JavaScript的开发难度 2. 解决浏览器的兼容性问题 3. 简化开发流程 经常使用Ajax框架 Prototype 一个纯粹的JavaScript函数库,对Ajax ...

  8. 最简单的视音频播放演示样例5:OpenGL播放RGB/YUV

    ===================================================== 最简单的视音频播放演示样例系列文章列表: 最简单的视音频播放演示样例1:总述 最简单的视音频 ...

  9. VC6 鼠标钩子 最简单样例

    Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的.而钩子是Windows系统中非常重要的系统接口,用它能够截获并处理送给其它应用程序的消息,来完毕普通应用程序 ...

  10. SQL SERVER 变量的使用和样例

    定义和使用局部变量:说明: 局部变量是用户可自定义的变量. 作用范围仅在程序内部. 局部变量的名称是用户自定义的,命名的局部变量名要符合SQL Server 2000标识符命名规则=>以@开 在 ...

随机推荐

  1. C# 优雅的处理TCP数据(心跳,超时,粘包断包,SSL加密 ,数据处理等)

    Tcp是一个面向连接的流数据传输协议,用人话说就是传输是一个已经建立好连接的管道,数据都在管道里像流水一样流淌到对端.那么数据必然存在几个问题,比如数据如何持续的读取,数据包的边界等. Nagle's ...

  2. 使用EasyPoi导出excel时如何避免导出null

    使用replace将null替换为空字符串 @Excel(name = "是否自动开始", replace = { "是_1", "否_0" ...

  3. KingbaseES 配置 Hugepage

    前言 大页的作用是为了提升内存管理的效率,减少内存管理资源消耗(节省pagetable的开销),特别是对于大内存的情况,同时,由于hugepage相对与4k的页面,它更不容易被交换出内存,因此,它的作 ...

  4. Java封装xml格式参数请求第三方接口

    Java封装xml格式参数请求第三方接口 1.引用包 import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers ...

  5. 【已解决】解决Python打开文件---路径报错问题(SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape)

    原因分析: 在windows系统当中读取文件路径可以使用\,但是在python字符串中\有转义的含义, 如\t可代表TAB,\n代表换行, 所以我们需要采取一些方式使得\不被解读为转义字符.目前有3个 ...

  6. mybatis使用Hashmap传递参数

    mapper 1 <!--传递map的key --> 2 <insert id="addUser2" parameterType="map"& ...

  7. zookeeper集群启动脚本文件

    cd bin/ vim myzk.sh for host in hadoop102 hadoop103 hadoop104 do ssh $host "source /etc/profile ...

  8. C# 做个Splash(启动屏幕)

    现在有好些splash的做法,我的比较简单,而且如果你的素材不错的话,应该可以做出很好的效果,这个教程不依赖任何第三方控件,直接使用vs的就行了,下面这个是预览图: 正文开始: 我们首先新建一个win ...

  9. 一文告诉你商业智能BI如何推动推动智慧物流发展

    随着网络消费的不断发展,推动了物流等相关产业的迅速发展,另外无论是2B业务还是2C业务的生产制造企业,对物流的要求都越来越高,尤其体现在对物流全程透明可视化的需求.商业智能BI平台的引入,大大提高了物 ...

  10. spring复习(一)框架概述和spring中基于xml的IOC配置

    1.spring框架概述和spring中基于xml的IOC配置 简介 Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Contr ...