React-Native 更新状态数组
React-Native Updating state array
我有一个状态,其中包含我从 API 中检索到的对象(玩家)数组,然后我使用地图函数
在屏幕上呈现用户头像
{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)
它 returns true
所以,理论上,我可以使用像 includes() 这样的数组函数。
知道问题出在哪里吗?
感谢您的宝贵时间!
您没有将正确的值传递给 setSelectedPlayers,应该这样做 setSelectedPlayers([...selectedPlayers, newPlayer])
。
这是一个优化版本,我使用状态的回调版本 setter 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>
我有一个状态,其中包含我从 API 中检索到的对象(玩家)数组,然后我使用地图函数
在屏幕上呈现用户头像 {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)
它 returns true
所以,理论上,我可以使用像 includes() 这样的数组函数。
知道问题出在哪里吗?
感谢您的宝贵时间!
您没有将正确的值传递给 setSelectedPlayers,应该这样做 setSelectedPlayers([...selectedPlayers, newPlayer])
。
这是一个优化版本,我使用状态的回调版本 setter 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>