编辑列表中的元素时,如何防止整个列表重新呈现?

时间:2019-07-08 18:15:29

标签: javascript reactjs

我创建了这个非常简单的应用程序,希望可以解释这个问题。

我尝试使用记忆和回调,但是我相信它是重新渲染的,因为一旦我输入文本输入,playerArr总是在变化。

我的实际列表只有15个元素,但是重新渲染会导致输入时它变得非常慢。

有什么建议吗?我有一个截止日期,我感到压力很大=(是否会回到非挂钩状态?还是实施redux?不确定性能因素。

function App() {
  const [player1, setPlayer1] = React.useState({
    firstName: "First",
    lastName: "Last ",
    id: uuidv4()
  });

  const [player2, setPlayer2] = React.useState({
    firstName: "First",
    lastName: "Last",
    id: uuidv4()
  });

  const [player3, setPlayer3] = React.useState({
    firstName: "First",
    lastName: "Last",
    id: uuidv4()
  });

  return (
    <div>
      <State
        player1={player1}
        player2={player2}
        player3={player3}
        setPlayer1={setPlayer1}
        setPlayer2={setPlayer2}
        setPlayer3={setPlayer3}
      />
    </div>
  );
}

//----------------------------------------------------------

export const State = React.memo(({player1, player2, player3, setPlayer1, setPlayer2, setPlayer3}) => {
  const playerArr = [player1, player2, player3];
  const setPlayerArr = [setPlayer1, setPlayer2, setPlayer3];

  return (
    <div>
      <Playlist
        playerArr={playerArr}
        setPlayerArr={setPlayerArr}
      />
    </div>
  );
});

//----------------------------------------------------------

export const Playlist = React.memo(({playerArr, setPlayerArr}) => {
  return (
    <div>
      {
        playerArr.map((player, index) => (
          <Player
            key={player.id}
            player={player}
            setPlayer={setPlayerArr[index]}
          />
        ))
      }
    </div>
  );
});

//----------------------------------------------------------

export const Player = React.memo(({player, setPlayer}) => {
  const handleOnChange = React.useCallback((event) => {
    const playerCopy = {...player};
    playerCopy[event.target.name] = event.target.value;
    setPlayer(playerCopy);
  }, [player, setPlayer]);

  return (
    <div>
      <input type={"text"} name={"firstName"} value={player.firstName} onChange={handleOnChange}/>
      <input type={"text"} name={"lastName"} value={player.lastName} onChange={handleOnChange}/>
    </div>
  );
});

编辑:我根据讨论内容编辑了应用。发生了同样的事情

1 个答案:

答案 0 :(得分:1)

无论您做什么,您的<App><Playlist>组件(即使已记忆)也将在每次有用户输入时重新呈现,因为这是您存储您的位置状态,这是可以预期的。

您能做的最好的事情就是记住每个<Player>组件,以便在重新呈现列表时,每个单独的列表项都不一定会重新呈现。为此,您可以将“ areEqual”函数作为第二个参数传递给React.memo。请参见React文档中的示例:https://reactjs.org/docs/react-api.html#reactmemo

在您的情况下,可能看起来像这样:

export const Player = React.memo(({player, setPlayer}) => {
  const handleOnChange = React.useCallback((event) => {
    const playerCopy = {...player};
    playerCopy[event.target.name] = event.target.value;
    setPlayer(playerCopy);
  }, [player, setPlayer]);

  return (
    <div>
      <input type={"text"} name={"firstName"} value={player.firstName} onChange={handleOnChange}/>
      <input type={"text"} name={"lastName"} value={player.lastName} onChange={handleOnChange}/>
    </div>
  );
}, (prevProps, nextProps) => {
  // Check to see if the data is the same
  if (prevProps.firstName === nextProps.firstName
    && prevProps.lastName === nextProps.lastName
    && prevProps.id === nextProps.id) {
    return true; // Return true if they ARE the same
  } else {
    return false; // Return false if they are NOT the same
  }
});

有时候,如果您要比较的数据是一个简单的字符串和/或数字集合,则可以使用JSON.stringify作为将其转换为字符串并比较字符串的简便方法:

export const Player = React.memo(({player, setPlayer}) => {
  const handleOnChange = React.useCallback((event) => {
    const playerCopy = {...player};
    playerCopy[event.target.name] = event.target.value;
    setPlayer(playerCopy);
  }, [player, setPlayer]);

  return (
    <div>
      <input type={"text"} name={"firstName"} value={player.firstName} onChange={handleOnChange}/>
      <input type={"text"} name={"lastName"} value={player.lastName} onChange={handleOnChange}/>
    </div>
  );
}, (prevProps, nextProps) => {
  // Check to see if the data is the same
  if (JSON.stringify(prevProps) === JSON.stringify(nextProps)) {
    return true; // Return true if they ARE the same
  } else {
    return false; // Return false if they are NOT the same
  }
});