我当时正在玩react-dev-tools chrome扩展程序,发现我所有的组件都在重新渲染。
App.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;
ColorPalette.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;
Color.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,这不是一个箭头函数,但是结果是相同的。我还传递了唯一的ID。有趣的是,当我通过const key = Math.random()
而不是const key = color.id
时,我的颜色分量没有重新渲染。因此,它与按键有关。我想了解为什么在传递唯一ID作为键时为什么重新渲染组件。
答案 0 :(得分:3)
阻止React功能组件重新呈现的唯一方法是使用React.memo
来记住该组件。此处的备注表示,如果组件的prop不变-使用===
运算符彼此严格相等,则组件的最后一个渲染输出将被重新使用,而不是重新渲染整个组件。
但是,当您谈论作为对象或函数的prop时,React.memo
本身会很棘手-严格的===
比较会检查引用相等性的值。这意味着对于deleteItem
之类的函数,需要使用React.useCallback
之类的东西来记忆引用本身,以使它们自己在渲染之间不会改变,这将使React.memo
跳闸并导致重新渲染在直觉上似乎不应该的情况。
如您所见,当您尝试跟踪功能,对象,组件等的记忆时,它很快变得非常复杂。
真的,有什么意义?
从备忘录中获得的性能提升(即使它们实现了)微乎其微。这是过早优化的经典案例,有时称为“ root of all evil”,因为它是不必要的时间浪费,几乎没有收获,而且增加了复杂性。
在优化的生产环境中进行响应本身的速度非常快,擅长解决差异问题,并且在大多数情况下,每秒可以将整个应用重新渲染数十次,而不会出现任何明显的速度下降。当您需要对性能产生实际,可衡量的影响时,才应该开始使用备忘录等功能来优化应用。
简而言之,您不必担心“不必要的”退货。
我会再强调一次:
请不要担心“不必要的”游戏。
严重。
PS:之所以对key
使用随机值,似乎消除了不必要的重新渲染,是因为每次组件渲染实际上是该组件的全新实例,而不是重新渲染相同的组件。 React在引擎盖下使用key
道具来跟踪渲染之间的哪个组件。如果该值不可靠,则意味着React每次都会在字面上渲染NEW组件。您基本上是在破坏所有旧组件,并从头开始重新创建它们,尽管使用相同的道具或其他任何东西,但是请不要误会,它们在渲染之间不是相同的组件。 (即使包括钩子在内的内部状态也将被删除)
答案 1 :(得分:1)
根据您所说的handleColorClick
道具已更改,这就是为什么要重新渲染组件的原因。由于您使用的是功能组件,并且在组件中具有钩子,因此当重新渲染组件时,功能handleColorClick
会重新定义,并且引用也会更改。这就是即使您将唯一的id作为键传递,也要重新渲染组件的原因。
为避免使用useCallback
钩子,除非提供给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;