Javascript 为什么输入的onChange事件会更改对象数组中的多个状态值?
我正在建立一个用户流,允许用户为他们玩的视频游戏输入统计数据。我的react组件呈现一个类似excel的表格,他们可以像excel电子表格一样手动输入统计数据,其中y轴是一列玩家,x轴是每个玩家的统计数据 当我为特定玩家更新特定属性时,每个玩家该属性的属性值也会改变。例如,如果我用5个进球更新球员A,团队中的每个其他球员也会有5个进球。这不应该发生 首先,我初始化matchStats对象:Javascript 为什么输入的onChange事件会更改对象数组中的多个状态值?,javascript,arrays,reactjs,object,Javascript,Arrays,Reactjs,Object,我正在建立一个用户流,允许用户为他们玩的视频游戏输入统计数据。我的react组件呈现一个类似excel的表格,他们可以像excel电子表格一样手动输入统计数据,其中y轴是一列玩家,x轴是每个玩家的统计数据 当我为特定玩家更新特定属性时,每个玩家该属性的属性值也会改变。例如,如果我用5个进球更新球员A,团队中的每个其他球员也会有5个进球。这不应该发生 首先,我初始化matchStats对象: initializeMatchStats = (numGames) => { const {
initializeMatchStats = (numGames) => {
const {matchInfo} = this.props;
const gameArray = new Array(numGames).fill('');
const matchStats = gameArray.map((game, i) => {
let statsWithKeys = {};
let gameInfo = {};
matchInfo.circuitStats.map(key => {
statsWithKeys[key.toLowerCase()] = 0
})
const players = new Array(matchInfo.playersAllowedInGame).fill({
stats: statsWithKeys
}).map(p => {
return {
...p,
dropdownOpen: false,
id: Math.random().toString(36)
}
})
gameInfo = {
players,
index: i + 1
}
return gameInfo
})
this.setState({matchStats, numGames, numGamesModalOpen: false, uploadManually: true}, () => console.log('matchStats: ', matchStats))
}
然后,在用户更改matchStats对象时更新它:
updateStatsManually = (val, player, game, header, e) => {
e.preventDefault();
const {matchStats} = this.state;
// matchStats is an array of games in each match. A game is made up of the players (and their respective stats) in the game.
const { matchInfo } = this.props;
const gameToUpdate = matchStats.find(g => g.index === game.index)
let playerToUpdate = gameToUpdate.players.find(p => p.id === player.id)
let newStats = playerToUpdate.stats;
newStats[header] = val;
playerToUpdate.stats = newStats;
gameToUpdate.players = [...gameToUpdate.players.filter(p => p.id !== player.id), playerToUpdate]
this.setState({
matchStats: [...matchStats.filter(g => g.index !== game.index), gameToUpdate]
})
}
以下是react代码块:
<Section>
{matchStats.find(g => g.index === game).players.map((player, i) => <Row key={i}>
{!uploadManually && <Column>
<Input disabled style={{textAlign: 'center'}} placeholder={player.name} />
</Column>}
{circuitStats.map((header, i) => <Column key={`${i}-${player.id}`}>
<Input id={`${i}-${player.id}-${header}`} value={player.stats[header.toLowerCase()]} disabled={!uploadManually} onChange={(e) => updateStatsManually(e.target.value, player, currentGame, header.toLowerCase())} />
</Column>)}
</Row>)}
</Section>
我希望当我为一个给定的玩家更改一个属性的输入值时,它只会更改该特定玩家的属性值。然而,它改变了每一个球员
我已经在这件事上纠结了一段时间,努力想知道我做错了什么。我认为这可能与.map函数中输入的呈现方式有关,但我尝试分离测试输入,结果是一样的。感谢您的帮助 第一个问题是以下几行:
const players = new Array(matchInfo.playersAllowedInGame).fill({
stats: statsWithKeys
}) // ... etc ...
通过将一个对象传递到中,每个元素都会填充对该单个对象的引用。堆栈片段在以下最小reprex中清楚地显示了这一点:
const arr=Array4.fill{age:11};
console.logJSON.stringifyarr;
arr[0],年龄42岁;
console.logJSON.stringifyarr;
console.logarr 第一个问题是以下几行:
const players = new Array(matchInfo.playersAllowedInGame).fill({
stats: statsWithKeys
}) // ... etc ...
通过将一个对象传递到中,每个元素都会填充对该单个对象的引用。堆栈片段在以下最小reprex中清楚地显示了这一点:
const arr=Array4.fill{age:11};
console.logJSON.stringifyarr;
arr[0],年龄42岁;
console.logJSON.stringifyarr;
console.logarr 假设你最多有5名球员。在这种情况下,这:
const players = new Array(matchInfo.playersAllowedInGame).fill().map(p => {
return {
stats: statsWithKeys,
dropdownOpen: false,
id: Math.random().toString(36)
}
})
不是像您预期的那样创建5个“statsWithKeys”,而是对同一个“statsWithKeys”的5个引用
解决此问题的最佳方法是直接在对象本身上使用扩展操作符:
const players = new Array(matchInfo.playersAllowedInGame).fill().map(p => {
return {
stats: { ...statsWithKeys },
dropdownOpen: false,
id: Math.random().toString(36)
}
});
假设你最多有5名球员。在这种情况下,这:
const players = new Array(matchInfo.playersAllowedInGame).fill().map(p => {
return {
stats: statsWithKeys,
dropdownOpen: false,
id: Math.random().toString(36)
}
})
不是像您预期的那样创建5个“statsWithKeys”,而是对同一个“statsWithKeys”的5个引用
解决此问题的最佳方法是直接在对象本身上使用扩展操作符:
const players = new Array(matchInfo.playersAllowedInGame).fill().map(p => {
return {
stats: { ...statsWithKeys },
dropdownOpen: false,
id: Math.random().toString(36)
}
});
你能说明这些结构是在哪里创建的吗?一定有一些别名。@ggorlen我在初始化matchStats对象的地方添加了代码块。希望这有帮助!这很有帮助,谢谢。新的ArraymatchInfo.playersAllowedInGame.fill{可能是问题所在。.fill只对整个shebang执行一个对象。将其更改为类似fill.mape=>{stats:statsWithKeys}…并让我知道它是否有效。很可能,您将只希望将原语传递到.fill.中。不幸的是,这似乎不起作用。我将其更改为:`const players=new ArraymatchInfo.players allowedingame.fill.mapp=>{return{stats:statsWithKeys,dropdownOpen:false,id:Math.random.toString36}}`应该是fill.mape=>{stats:statsWithKeys};注意额外的参数。您的更改也起到了作用吗?问题是statsWithKeys仍然只是一个对象,所以这是一个问题。您还必须在地图中初始化该对象。基本上,任何时候只要创建一个对象,它都会被别名,因此有多个别名问题需要解决。您可以吗这些结构是在什么地方创建的?肯定有一些别名。@ggorlen我在初始化matchStats对象的地方添加了代码块。希望这会有帮助!非常有帮助,谢谢。新的ArraymatchInfo.playersAllowedInGame.fill{可能是问题所在。.fill只对整个shebang执行一个对象。将其更改为类似fill.mape=>{stats:statsWithKeys}…并让我知道它是否有效。很可能,您将只希望将原语传递到.fill.中。不幸的是,这似乎不起作用。我将其更改为:`const players=new ArraymatchInfo.players allowedingame.fill.mapp=>{return{stats:statsWithKeys,dropdownOpen:false,id:Math.random.toString36}}`应该是fill.mape=>{stats:statsWithKeys};注意额外的参数。您的更改也起到了作用吗?问题是statsWithKeys仍然只是一个对象,所以这是一个问题。您还必须在地图中初始化该对象。基本上,任何时候只要创建一个对象,它都会被别名,因此需要解决多个别名问题。