You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何React memo自定义相等函数需使用JSON.stringify?

问题

我有一个如下的ChatMessage组件:

const ChatMessage = memo(({messageObj, replyTo, newChatData, storedUsers, handleDeleteMessage, chatId}, arePropsEqual)

其中messageObj是类似{id: 3, text: "test"}的普通JavaScript对象。

自定义相等函数arePropsEqual在添加JSON.stringify后能正常工作,仅当messageObj的实际值变化时才重新渲染ChatMessage:

function arePropsEqual(oldProps, newProps) {
    // 如预期输出true
    console.log(JSON.stringify(oldProps.messageObj) === JSON.stringify(newProps.messageObj));
    return JSON.stringify(oldProps.messageObj) === JSON.stringify(newProps.messageObj)
}

而此前直接使用oldProps.messageObj === newProps.messageObj的相等函数无法按预期阻止重渲染。请问为何需要JSON.stringify?它为何能解决普通JavaScript对象的比较问题?

原因解析

1. 直接用===无效的核心原因

JavaScript里,===对对象这类引用类型的比较逻辑是看内存地址,不是看内容:

  • 哪怕两个对象的键值完全一样,只要它们是内存里的不同实例,===就会返回false。
  • 比如父组件每次渲染时,如果messageObj是新生成的对象(哪怕内容和之前没差),它的引用地址就变了,这时候oldProps.messageObj === newProps.messageObj会返回false,导致memo误以为属性变了,触发不必要的重渲染。

2. JSON.stringify的作用原理

JSON.stringify会把对象转换成对应的JSON字符串,这个字符串只和对象的实际键值内容绑定:

  • 只要两个对象的键值对完全一致(键的顺序也一致时),它们的JSON字符串就完全相同,用===比较字符串就能得到true。
  • 这样就绕过了引用地址的对比,直接校验对象的实际内容,实现了只有当messageObj内容真的变化时,才让memo允许组件重渲染的效果。

注意事项:JSON.stringify的局限

这个方法能解决当前问题,但存在一些潜在问题:

  • 如果对象的键顺序不同(比如{a:1, b:2}和{b:2, a:1}),JSON.stringify的结果会不一样,导致误判。
  • 对象里如果包含undefined、函数、Symbol类型的值,JSON.stringify会直接忽略这些属性,可能导致比较结果不准确。
  • 性能开销:如果对象体积大,频繁调用JSON.stringify会增加性能消耗,不如用专门的深比较工具(比如lodash的isEqual)高效。

内容的提问来源于stack exchange,提问作者Coding Ninja123211

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:10:17