![](/img/trans.png)
[英]Child Components not re-rendering despite a state-change in Parent
[英]Why are all my child components re-rendering despite having keys?
我在玩 react-dev-tools chrome 扩展,发现我所有的组件都在重新渲染。
应用程序.js
import React from 'react';
import './App.css';
import Header from './components/molecules/Header/Header';
// import { colorListGenerator } from './core-utils/helpers';
import ColorPalette from './components/organisms/ColorPalette/ColorPalette';
export const colorListGenerator = (n) => {
let colorArray = []
for(let i=0; i<n; i++) {
let randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
let id="id" + Math.random().toString(16).slice(2)
console.log(typeof(id), id)
let color = {
id: id,
hex: randomColor
}
colorArray.push(color);
}
return colorArray
}
const App = () => {
const colors=colorListGenerator(10);
return (
<div className="App">
<Header/>
<ColorPalette colorPalette={colors} />
</div>
);
}
export default App;
调色板.js
/* eslint-disable eqeqeq */
import React from 'react';
import Color from '../../atoms/Color';
import './ColorPalette.css';
const ColorPalette = ({ colorPalette }) => {
const [colors, setColors] = React.useState(colorPalette);
// const handleColorClick = (event) => {
// const id = event.currentTarget.getAttribute('id')
// const index = colors.findIndex(item => item.id == id);
// setColors(colors.filter(item => item.id != id))
// }
const deleteItem = (id) => {
setColors(colors.filter(item => item.id != id))
}
return (
<div className={'colorPalette'}>
{colors && colors.map((color, index) => {
// const key = index
const key = color.id
return <Color
key={key}
color={color.hex}
colorKey={key}
handleColorClick = {() => {deleteItem(color.id)}}
/> })}
</div>
)
}
// export default React.memo(ColorPalette);
export default ColorPalette;
颜色.js
import React from 'react';
import './Color.css';
import deleteIcon from '../../../delete-icon.png'
const Color = ({ color, colorKey, handleColorClick }) => {
return (
<div className="color"
style={{ backgroundColor: color }}
// no need to mention key here
// key={colorKey}
id={colorKey}
onClick={handleColorClick} >
<p> {colorKey} </p>
<img src={deleteIcon}
alt={'delete'}
className="delete"
/>
</div>
)
}
// export default React.memo(Color);
export default Color;
当我使用分析器检查为什么在删除单个项目后我的所有“颜色”组件都重新渲染时,它抱怨 handleColorClick 道具已更改。 我将deleteItem更改为handleColorClick,它不是箭头function,但结果是一样的。 我还传递了唯一的 ID。 有趣的是,当我通过const key = Math.random()
而不是const key = color.id
,我的 Color 组件不会重新渲染。 所以它与键有关。 我想了解为什么当我将唯一 ID 作为键传递时我的组件会重新渲染。
防止 React 功能组件重新渲染的唯一方法是使用React.memo
来记忆组件。 这里的记忆意味着如果组件的 props 没有改变 - 它们使用===
运算符严格等价 - 那么组件的最后一次渲染 output 将被重新使用,而不是重新渲染整个组件。
但是,当您谈论 object 或函数的道具时, React.memo
本身会变得很棘手 - 严格===
比较检查引用相等性的值。 这意味着对于像deleteItem
这样的函数,需要使用像React.useCallback
这样的东西来记忆引用本身,这样它们本身就不会在渲染之间发生变化,这将导致React.memo
并导致在直觉上看起来应该的情况下重新渲染不。
正如你所看到的,当你试图记录你的函数、对象、组件等时,它很快开始变得相当复杂。
真的,有什么意义呢?
你从记忆中获得的性能提升——如果它们实现的话——是微乎其微的。 这是过早优化的典型案例,有时被称为“万恶之源”,因为它是一种不必要的时间消耗,几乎没有收获,而且增加了复杂性的代价。
React 本身在其优化的生产构建中非常快,擅长解决差异,并且在大多数情况下,每秒可以重新渲染整个应用程序数十次,而不会出现任何明显的减速。 仅当您对需要解决的性能产生实际的、可衡量的影响时,您才应该开始使用诸如 memoization 之类的东西来优化您的应用程序。
简而言之,您无需担心“不必要的”重新渲染。
为了强调,我再说一遍:
不要担心“不必要的”渲染。
严重地。
PS:使用随机值作为key
看起来似乎消除了不必要的重新渲染的原因是因为每次渲染组件时,它实际上都是该组件的全新实例,而不是被重新渲染的相同组件。 React 在底层使用key
prop 来跟踪渲染之间的哪个组件。 如果该值不可靠,则意味着 React 每次都在渲染新组件。 您基本上是在销毁所有旧组件并从头开始重新创建它们,尽管使用相同的道具或其他任何东西,但请不要误会,它们在渲染之间不是相同的组件。 (甚至包括挂钩在内的内部 state 也会被擦除)
根据您所说, handleColorClick
道具已更改,这就是重新渲染组件的原因。 由于您在组件中使用功能组件和钩子,因此当组件重新渲染时,function handleColorClick
将再次重新定义,并且引用正在更改。 这就是为什么即使您将唯一 ID 作为键传递,组件也会重新渲染的原因。
为了避免这种情况,您可以使用useCallback
挂钩,这将帮助您不获取新的 function 引用,除非提供给useCallback
挂钩的依赖项发生变化
/* eslint-disable eqeqeq */
import React, {useCallback} from 'react';
import Color from '../../atoms/Color';
import './ColorPalette.css';
const ColorPalette = ({ colorPalette }) => {
const [colors, setColors] = React.useState(colorPalette);
// const handleColorClick = (event) => {
// const id = event.currentTarget.getAttribute('id')
// const index = colors.findIndex(item => item.id == id);
// setColors(colors.filter(item => item.id != id))
// }
const deleteItem = useCallback((id) => {
setColors(colors.filter(item => item.id != id))
}, [])
return (
<div className={'colorPalette'}>
{colors && colors.map((color, index) => {
// const key = index
const key = color.id
return <Color
key={key}
color={color.hex}
colorKey={key}
handleColorClick = {() => {deleteItem(color.id)}}
/> })}
</div>
)
}
// export default React.memo(ColorPalette);
export default ColorPalette;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.