为何React组件在传入的Props对象被修改后不重新渲染?
问题分析与解答
先把你的代码整理成更易读的格式:
JavaScript 代码
import React from 'react'; import { render } from 'react-dom'; const x = []; const App = props => <div>{JSON.stringify(x)}</div>; render(<App queries={x} />, document.getElementById('root')); setInterval(x => x.push(Math.random()), 1000, x);
HTML 代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>React App</title> </head> <body> <div id="root"></div> </body> </html>
为什么组件不重新渲染,但Dev Tools能看到更新?
这是React重渲染机制和引用类型特性共同导致的典型问题:
React的重渲染触发逻辑:React组件只会在两种场景下触发重渲染:
- 组件自身的
state通过setState/useState更新时; - 父组件传递的
props的引用发生变化时。
你用的数组
x是引用类型,x.push(Math.random())只是修改了数组内部的元素,但数组本身的内存引用(指针)完全没变。React做props浅比较时,发现queries的引用和之前一致,就判定props没有更新,自然不会触发App组件的重渲染。- 组件自身的
React Dev Tools的特殊行为:当你关闭再重新打开Dev Tools时,它会主动读取当前
x变量的实际内容,不依赖React的渲染快照。所以它能直接获取到数组的最新值,哪怕组件没重渲染。
解决办法
推荐用React的状态管理来处理这种需要动态更新的变量,这是React的标准用法:
方案1:使用函数组件的useState+useEffect
import React, { useState, useEffect } from 'react'; import { render } from 'react-dom'; const App = () => { // 把x转为组件内部状态 const [x, setX] = useState([]); useEffect(() => { // 开启定时器,每次更新都创建新数组(改变引用) const timer = setInterval(() => { setX(prevX => [...prevX, Math.random()]); }, 1000); // 组件卸载时清理定时器,避免内存泄漏 return () => clearInterval(timer); }, []); return <div>{JSON.stringify(x)}</div>; }; render(<App />, document.getElementById('root'));
方案2:强制更新(不推荐,非React常规写法)
如果一定要用外部变量,每次更新时需要创建新的数组引用,再重新调用render:
import React from 'react'; import { render } from 'react-dom'; let x = []; const App = props => <div>{JSON.stringify(props.queries)}</div>; render(<App queries={x} />, document.getElementById('root')); setInterval(() => { // 创建新数组,改变引用 x = [...x, Math.random()]; // 重新渲染组件 render(<App queries={x} />, document.getElementById('root')); }, 1000);
总结一下:React是靠引用变化来感知状态/Props更新的,直接修改引用类型内部值无法触发重渲染,必须通过状态管理或者改变引用的方式让React感知到变化。
内容的提问来源于stack exchange,提问作者mohsinulhaq
相关产品推荐
相关产品推荐

