我有一个相当简单的组件示例(Hello.js),该组件呈现三个组件,每个组件都有不同的ID(Speaker.js)。我有一个select
timestamp,
sum(case when charge = 'Yearly' then charge else 0 end) yearly,
sum(case when charge = 'Monthly' then charge else 0 end) monthly
from charges
group by timestamp
,我从Speaker.js返回。我认为使用React.memo和React.useCallback会在只有一个更改时阻止所有三个重新渲染,但是可悲的是,您可以从Speaker.js的console.log中看到,单击三个按钮中的任何一个都会导致这三个渲染。
这是stackblitz上的问题示例:
https://stackblitz.com/edit/react-dmclqm
Hello.js
clickFunction
Speaker.js
import React, { useCallback, useState } from "react";
import Speaker from "./Speaker";
export default () => {
const speakersArray = [
{ name: "Crockford", id: 101, favorite: true },
{ name: "Gupta", id: 102, favorite: false },
{ name: "Ailes", id: 103, favorite: true },
];
const [speakers, setSpeakers] = useState(speakersArray);
const clickFunction = useCallback((speakerIdClicked) => {
var speakersArrayUpdated = speakers.map((rec) => {
if (rec.id === speakerIdClicked) {
rec.favorite = !rec.favorite;
}
return rec;
});
setSpeakers(speakersArrayUpdated);
},[speakers]);
return (
<div>
{speakers.map((rec) => {
return (
<Speaker
speaker={rec}
key={rec.id}
clickFunction={clickFunction}
></Speaker>
);
})}
</div>
);
};
答案 0 :(得分:2)
因为触发clickFunction
会更新导致重新创建此功能的扬声器,要解决此问题,您需要从speakers
依赖项中删除clickFunction
并从{{1} } 打回来。
解决方案:
从“反应”中导入React,{useCallback,useState,useEffect};
setState
和扬声器组件:
import Speaker from "./Speaker";
export default () => {
const [speakers, setSpeakers] = useState([
{ name: "Crockford", id: 101, favorite: true },
{ name: "Gupta", id: 102, favorite: false },
{ name: "Ailes", id: 103, favorite: true },
]);
const clickFunction = useCallback((speakerIdClicked) => {
setSpeakers(currentState=>currentState.map((rec) => {
if (rec.id === speakerIdClicked) {
rec.favorite = !rec.favorite;
return {...rec};
}
return rec
}));
},[]);
useEffect(()=>{
console.log("render")
})
return (
<div>
{speakers.map((rec) => {
return (
<Speaker
speaker={rec}
key={rec.id}
clickFunction={clickFunction}
></Speaker>
);
})}
</div>
);
};
答案 1 :(得分:2)
进一步思考后,我认为我的回答可能并不完全正确:没有[speakers]
依赖项将无法按预期工作。
两件事:
传递给 [speakers]
的{{1}}依赖项导致每次useCallback
更改时都会重新创建该函数,并且由于回调本身调用speakers
,它将在每个渲染器上重新创建。
如果您修复了#1,则Speaker组件将根本不会重新渲染,因为它们将收到相同的setSpeakers
道具。 speaker
发生更改的事实不会触发重新渲染,因为speaker.favorite
仍然是同一对象。要解决此问题,请让您的click函数返回speaker
翻转后的rec
的副本,而不是仅在现有对象中切换它:
favorite