简体   繁体   English

当某个 prop 发生变化时,如何避免重新渲染功能组件?

[英]How to avoid re-rendering a functional component when a certain prop changes?

I have a PlayArea component with a number of Card components as children, for a card game.我有一个 PlayArea 组件,其中有许多 Card 组件作为子级,用于纸牌游戏。

The position of the cards is managed by the PlayArea, which has a state value called cardsInPlay , which is an array of CardData objects including positional coordinates among other things.卡片的位置由 PlayArea 管理,它有一个称为cardsInPlay的状态值,它是一个CardData对象数组,包括位置坐标等。 PlayArea passes cardsInPlay and setCardsInPlay (from useState ) into each Card child component. PlayArea 将cardsInPlaysetCardsInPlay (来自useState )传递给每个 Card 子组件。

Cards are draggable, and while being dragged they call setCardsInPlay to update their own position.卡片是可拖动的,在拖动时它们会调用setCardsInPlay来更新它们自己的位置。

The result, of course, is that cardsInPlay changes and therefore every card re-renders.当然,结果是cardsInPlay发生了变化,因此每张卡片都会重新呈现。 This may grow costly if a hundred cards make it out onto the table.如果一百张牌出现在桌面上,这可能会增加成本。

How can I avoid this?我怎样才能避免这种情况? Both PlayArea and Card are functional components. PlayArea 和 Card 都是功能组件。

Here's a simple code representation of that description:这是该描述的简单代码表示:

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} />);
   });

          

It depends on how you pass cardsInPlay to each Card component.这取决于您如何将cardsInPlay传递给每个Card组件。 It doesn't matter if the array in state changes as long as you pass only the required information to child.只要您只将所需的信息传递给 child,状态中的数组是否发生变化都没有关系。

Eg:例如:

<Card positionX={cardsInPlay[card.id].x} positionY={cardsInPlay[card.id].y} /> 

will not cause a re-render, because even i the parent array changes, the instance itself is not getting a new prop.不会导致重新渲染,因为即使父数组发生变化,实例本身也不会获得新的道具。 But if you pass the whole data to each component :但是,如果您将整个数据传递给每个组件:

<Card cardsInPlay={cardsInPlay} /> 

it will cause all to re-render because each Card would get a new prop for every render as no two arrays,objects are equal in Javascript.这将导致所有重新渲染,因为每张Card都会为每次渲染获得一个新道具,因为没有两个数组,对象在 Javascript 中是相等的。

PS : Edited after seeing sample code PS:看到示例代码后编辑

The problem is you're passing the entire cardsInPlay array to each Card , so React.memo() will still re-render each card because the props have changed.问题是你将整个cardsInPlay数组传递给每个Card ,所以React.memo()仍然会重新渲染每张卡片,因为props已经改变了。 Only pass the element that each card needs to know about and it will only re-render the card that has changed.只传递每张卡片需要知道的元素,它只会重新渲染已更改的卡片。 You can access the previous cardsInPlay using the functional update signature of setCardsInPlay() :您可以使用setCardsInPlay()功能更新签名访问以前的cardsInPlay

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} />);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 数组道具更改时反应组件不重新渲染 - React component not re-rendering when array prop changes 当 redux state 更改时,功能组件不会重新渲染 - functional component is not re-rendering when redux state changes 当我将对象作为道具传递给子组件时如何避免重新渲染? - How to avoid re-rendering when i pass an object as prop to child component? 当路由发生变化时,我可以避免重新渲染父路由处理程序组件吗? - Can I avoid re-rendering parent route handler component when the route changes? Vue.js 性能:避免子组件列表发生变化时父组件重新渲染 - Vue.js performance: avoid parent component re-rendering when the list of children components changes 将 props 传递给子组件时避免组件重新渲染 - Avoid component re-rendering when passing props to child component 在 prop 更改时重新渲染组件 - Re-rendering a component on prop change 如何防止在 React 中的功能组件中重新渲染 - How to prevent re-rendering in functional component in React React:如何避免使用钩子重新渲染组件,该钩子始终返回相同的值但会改变其内部状态 - React: how to avoid re-rendering a component with a hook that returns always the same value but changes its inner state 为什么我的功能组件没有重新渲染? - Why is my functional component not re-rendering?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM