React 如何更新他的状态?
How is React updating his state?
我有一个关于 React 以及必须如何更新状态的问题。
假设我们有一个 class Players,在其状态中包含一个名为 players 的对象数组。我们想更新这个数组中的一个玩家。我会这样做的:
class Players extends Component {
state = {
players: []
}
updatePlayer = id => {
const players = this.state.players.map(player => {
player.updated = player.id === id ? true:false;
return player
});
this.setState({players: players});
}
}
但是我的同事就是这样做的,而且还有效:
updatePlayer = id => {
const playerObj = this.state.players.find(item => {
return item.id === id
})
if (playerObj) {
playerObj.updated = true
this.setState({ playerObj })
}
}
React 的函数 setState 更新了 players 数组,但没有明确告知要这样做。所以,我有两个问题:
- 是否使用查找函数的引用,并使用它来更新玩家数组?
- 推荐其中一种方法吗?
谢谢大家的解释!
这两个都不对,因为你在变异状态。
最好的方法是创建这个数组的深层副本(只是克隆),然后对这个克隆数组进行一些更改
你也可以使用 lodash _.cloneDeep();
例如
class Example extends React.Component {
state = {
players: [
{id: 0, name: 'John'};
]
};
updatePlayer = id => {
const { players } = this.state;
const clonePlayers = players.map(a => ({...a}));
const player = clonePlayers.find(playerId => playerId === id);
player.name = 'Jack';
this.setState(() => ({
players: clonePlayers
}));
}
render() {
return (
<div>some</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
是的,都是引用。所有 javascript 对象都是引用,因此无论何时进行查找,您都会获得对该对象的引用,因此对其进行变异将对其进行更新。
const players = this.state.players.map(player => {
return { ...player, updated: player.id === id };
});
this.setState({players: players});
至于推荐的方法,您应该坚持使用您明确更新您关心的状态变量的方法。
不同之处在于第二个代码段误用了 setState
来触发更新,因为它使用了 playerObj
虚拟 属性。这可以通过 forceUpdate
.
来实现
这两种方式都不正确。不可变状态在 React 中被提升为一种约定。改变现有状态可能会导致期望状态不可变的组件出现不正确的行为。它们改变现有的 player
对象,并且新的 player.update
值将在使用该对象的任何地方使用,即使这是不受欢迎的。
一种惯用的方法是在状态中使用不可变对象:
updatePlayer = id => {
this.setState(({ players }) => ({
players: players.map(player => ({
...player,
updated: player.id === id
}));
});
}
注意 setState
是异步的,必须使用 updater function 来避免可能的竞争条件。
好吧,基本上它们是不一样的,你同事的代码能正常工作只是因为他使用的是对象的旧引用。那么,让我们来看看:
updatePlayer = id => {
const players = this.state.players.map(player => {
player.updated = player.id === id ? true:false;
return player
});
this.setState({players: players});
}
在您的函数中,您正在使用旧数组创建一个新的 array
,这是执行此操作的正确方法。
updatePlayer = id => {
const playerObj = this.state.players.find(item => {
return item.id === id
})
if (playerObj) {
playerObj.updated = true
this.setState({ playerObj })
}
}
你的朋友在这里编辑他使用 find
获得的对象的引用,然后保存一个 playerObj
,它只不过是你想要的数组中玩家的引用编辑。在此之后你应该注意到新状态将类似于
this.state = {
players: [p1, p2 ,p3, p4], // each p is a player.
//notice that playerObj is now a reference to some of the P on the players array
playerObj: {
...playerstuff,
updated: true
}
}
希望对您有所帮助:)
我有一个关于 React 以及必须如何更新状态的问题。 假设我们有一个 class Players,在其状态中包含一个名为 players 的对象数组。我们想更新这个数组中的一个玩家。我会这样做的:
class Players extends Component {
state = {
players: []
}
updatePlayer = id => {
const players = this.state.players.map(player => {
player.updated = player.id === id ? true:false;
return player
});
this.setState({players: players});
}
}
但是我的同事就是这样做的,而且还有效:
updatePlayer = id => {
const playerObj = this.state.players.find(item => {
return item.id === id
})
if (playerObj) {
playerObj.updated = true
this.setState({ playerObj })
}
}
React 的函数 setState 更新了 players 数组,但没有明确告知要这样做。所以,我有两个问题:
- 是否使用查找函数的引用,并使用它来更新玩家数组?
- 推荐其中一种方法吗?
谢谢大家的解释!
这两个都不对,因为你在变异状态。 最好的方法是创建这个数组的深层副本(只是克隆),然后对这个克隆数组进行一些更改
你也可以使用 lodash _.cloneDeep();
例如
class Example extends React.Component {
state = {
players: [
{id: 0, name: 'John'};
]
};
updatePlayer = id => {
const { players } = this.state;
const clonePlayers = players.map(a => ({...a}));
const player = clonePlayers.find(playerId => playerId === id);
player.name = 'Jack';
this.setState(() => ({
players: clonePlayers
}));
}
render() {
return (
<div>some</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
是的,都是引用。所有 javascript 对象都是引用,因此无论何时进行查找,您都会获得对该对象的引用,因此对其进行变异将对其进行更新。
const players = this.state.players.map(player => {
return { ...player, updated: player.id === id };
});
this.setState({players: players});
至于推荐的方法,您应该坚持使用您明确更新您关心的状态变量的方法。
不同之处在于第二个代码段误用了 setState
来触发更新,因为它使用了 playerObj
虚拟 属性。这可以通过 forceUpdate
.
这两种方式都不正确。不可变状态在 React 中被提升为一种约定。改变现有状态可能会导致期望状态不可变的组件出现不正确的行为。它们改变现有的 player
对象,并且新的 player.update
值将在使用该对象的任何地方使用,即使这是不受欢迎的。
一种惯用的方法是在状态中使用不可变对象:
updatePlayer = id => {
this.setState(({ players }) => ({
players: players.map(player => ({
...player,
updated: player.id === id
}));
});
}
注意 setState
是异步的,必须使用 updater function 来避免可能的竞争条件。
好吧,基本上它们是不一样的,你同事的代码能正常工作只是因为他使用的是对象的旧引用。那么,让我们来看看:
updatePlayer = id => {
const players = this.state.players.map(player => {
player.updated = player.id === id ? true:false;
return player
});
this.setState({players: players});
}
在您的函数中,您正在使用旧数组创建一个新的 array
,这是执行此操作的正确方法。
updatePlayer = id => {
const playerObj = this.state.players.find(item => {
return item.id === id
})
if (playerObj) {
playerObj.updated = true
this.setState({ playerObj })
}
}
你的朋友在这里编辑他使用 find
获得的对象的引用,然后保存一个 playerObj
,它只不过是你想要的数组中玩家的引用编辑。在此之后你应该注意到新状态将类似于
this.state = {
players: [p1, p2 ,p3, p4], // each p is a player.
//notice that playerObj is now a reference to some of the P on the players array
playerObj: {
...playerstuff,
updated: true
}
}
希望对您有所帮助:)