我有一个PlayArea组件,其中有许多作为孩子的Card组件,用于打牌游戏。
纸牌的位置由PlayArea管理,PlayArea的状态值为cardsInPlay
,它是CardData
对象的数组,其中包括位置坐标。 PlayArea将cardsInPlay
和setCardsInPlay
(来自useState
)传递到每个Card子元素。
卡是可拖动的,在被拖动时,它们会调用setCardsInPlay
来更新自己的位置。
当然,结果是cardsInPlay
发生了变化,因此每张纸牌都会重新出现。如果将一百张纸牌放在桌子上,这可能会增加成本。
如何避免这种情况? PlayArea和Card都是功能组件。
以下是该描述的简单代码表示形式:
const PlayArea = () => {
const [cardsInPlay, setCardsInPlay] = useState([]);
return (
<>
{ cardsInPlay.map(card => (
<Card
key={card.id}
card={card}
cardsInPlay={cardsInPlay}
setCardsInPlay={setCardsInPlay} />
}
</>
);
}
const Card = React.memo({card, cardsInPlay, setCardsInPlay}) => {
const onDrag = (moveEvent) => {
setCardsInPlay(
cardsInPlay.map(cardInPlay => {
if (cardInPlay.id === card.id) {
return {
...cardInPlay,
x: moveEvent.clientX,
y: moveEvent.clientY
};
}
return cardInPlay;
}));
};
return (<div onDrag={onDrag} />);
});
答案 0 :(得分:2)
这取决于您如何将cardsInPlay
传递给每个Card
组件。只要您仅将所需的信息传递给child,状态数组就不会改变。
例如:
<Card positionX={cardsInPlay[card.id].x} positionY={cardsInPlay[card.id].y} />
不会导致重新渲染,因为即使父数组更改了,实例本身也不会获得新的支持。但是,如果您将整个数据传递给每个组件:
<Card cardsInPlay={cardsInPlay} />
这将导致所有人重新渲染,因为每个Card
每次渲染都会获得一个新的道具,因为没有两个数组,Javascript中的对象相等。
P.S:看到示例代码后进行编辑
答案 1 :(得分:1)
问题是您要将整个cardsInPlay
数组传递给每个Card
,因此React.memo()
仍将重新渲染每张卡片,因为props
具有已更改。仅传递每张卡需要了解的元素,它只会重新呈现已更改的卡。您可以使用cardsInPlay
的{{3}}签名访问上一个setCardsInPlay()
:
const PlayArea = () => {
const [cardsInPlay, setCardsInPlay] = useState([]);
const cards = cardsInPlay.map(
card => (
<Card
key={card.id}
card={card}
setCardsInPlay={setCardsInPlay} />
)
);
return (<>{cards}</>);
};
const Card = React.memo(({ card, setCardsInPlay }) => {
const onDrag = (moveEvent) => {
setCardsInPlay(
cardsInPlay => cardsInPlay.map(cardInPlay => {
if (cardInPlay.id === card.id) {
return {
...cardInPlay,
x: moveEvent.clientX,
y: moveEvent.clientY
};
}
return cardInPlay;
})
);
};
return (<div onDrag={onDrag} />);
});