React-Native更新状态数组

时间:2020-05-20 14:32:26

标签: arrays reactjs react-native react-state-management

我的状态是保存从API中检索到的对象(玩家)数组,然后使用map函数在屏幕上呈现用户头像

   {players.map(player => {
      return (
        <TouchableOpacity
          key={player._id}
          style={selectedPlayers.inclues(player) ? styles.userAvatarContainerSelected : styles.userAvatarContainer}
          onPress={() => handlePlayerAvatarClick(player)}
        >
          <Image
            source={{
              uri: player.avatar_url
            }}
            style={styles.userAvatar}
          />
        </TouchableOpacity>
      );
    })}

我的问题是,当我点击按钮时,我想更新状态为selectedPlayers的状态,以便我可以相应地更新样式,然后将状态取回API。 我将状态初始化为const [playersAvatars, setPlayersAvatars] = useState([]);

handlePlayerAvatarClick函数为:

function handlePlayerAvatarClick(newPlayer) {

    if (newPlayer in selectedPlayers) {
      const arrayWithRemovedPlayer = selectedPlayers.filter(player => player._id.equals(newPlayer._id));

      setSelectedPlayers(arrayWithRemovedPlayer);
    }

    setSelectedPlayers(...selectedPlayers, newPlayer);
  }

我收到一条错误消息,说selectedPlayers.includes()不是一个函数,我没有问题,如果我运行Array.isArray(selectedPlayers)它将返回true,因此,从理论上讲,我可以使用include()之类的数组函数。

对这个问题有什么想法吗?

谢谢您的时间!

1 个答案:

答案 0 :(得分:1)

您没有将正确的值传递给setSelectedPlayers,应该做setSelectedPlayers([...selectedPlayers, newPlayer])

这是一个优化的版本,在这里我使用状态设置器setSomeState(oldvalue=>newValue的回调版本:

//using React.memo will make Player a pure
//  component and won't re render if props didn't change
const Player = React.memo(function Player({
  player,
  isSelected,
  handlePlayerAvatarClick,
}) {
  const r = React.useRef(0);
  r.current++;
  return (
    <li
      onClick={handlePlayerAvatarClick(player)}
      style={{ cursor: 'pointer' }}
    >
      rendered:{r.current} times, name: {player.name}, is
      selected:
      {isSelected.toString()}
    </li>
  );
});
const players = [
  { id: 1, name: '1', completed: false },
  { id: 2, name: '2', completed: false },
];

function App() {
  const [
    selectedPlayers,
    setSelectedPlayers,
  ] = React.useState([]);
  //use callback so the handler never changes
  const handlePlayerAvatarClick = React.useCallback(
    (player) => () =>
      setSelectedPlayers((selectedPlayers) =>
        selectedPlayers.includes(player)
          ? selectedPlayers.filter((p) => p !== player)
          : [...selectedPlayers, player]
      ),
    []
  );
  return (
    <ul>
      {players.map((player) => (
        <Player //player is pure and won't re render if nothing changed
          key={player.id}
          player={player}
          isSelected={selectedPlayers.includes(player)}
          handlePlayerAvatarClick={handlePlayerAvatarClick}
        />
      ))}
    </ul>
  );
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>


<div id="root"></div>