ReactJS - 使用切片更新状态后视图未重新呈现
ReactJS - View not re-rendered after updating state using slice
这是我的 class Content
,在 App.js
中渲染。我已通读 ReactJS 教程并了解我需要在不突变的情况下更改数据。
https://reactjs.org/tutorial/tutorial.html
但即使我使用 slice
,应用程序也不会在状态更改时重新呈现。
这 class 管理一副纸牌,如下所示:
//omitted imports
import main_deck from ...
import side_deck from ...
export default class Content extends Component {
constructor(props) {
super(props);
this.moveToMainDeck = this.moveToMainDeck.bind(this);
this.state = {
mainDeck : main_deck,
sideDeck : side_deck
}
}
moveToMainDeck(card) {
const fromDeck = this.state.sideDeck.slice(); //copy the state data
const toDeck = this.state.mainDeck.slice();
var movable = checkMovability(fromDeck, toDeck, card);
if (movable[0] === 1) { //use slice instead of splice
var newMain = toDeck.slice(0, movable[1]).concat([card]).concat(toDeck.slice(movable[1]));
var cardIndexInSideDeck = fromDeck.indexOf(card);
var newSide = fromDeck.slice(0, cardIndexInSideDeck).concat(fromDeck.slice(cardIndexInSideDeck + 1));
this.setState({ mainDeck : newMain, sideDeck : newSide });
}
else if (movable[0] === -1)
alert("Unable to move. Main Deck is full.");
else //movable[0] === 0
alert("Unable to move. Limit reached for this card in Main Deck.");
}
render() {
return (
<div><MainDeck ... /><SideDeck ... /></div>
);
}
}
使用上面的代码,我通过打印出 JSON 数组来测试状态数据,在 this.setState
之后状态确实发生了变化,但是视图仍然没有重新渲染。
但是,我通过将 slice()
替换为 push()
进行了测试,状态更改后所有内容都会重新呈现,如下所示:fromDeck.push(card);
或 toDeck.push(card);
任何人请告诉我我正在使用的 slice
有什么问题。非常感谢!
这是因为 slice 函数创建了一个浅拷贝,这意味着它只复制对象的结构,这进一步意味着不复制对象的字段,只共享引用,所以当你在复制对象中更改原始对象时对象也会改变,所以当 react 比较它发现的差异时 none 因此它不会重新渲染。
//Example
var one=[{'a':'first'},{'b':'second'}]
var two=one.slice()
var three=two.slice(0,1)
three[0].a='third'
//Now in all variables (one,two,three) a will have value of 'three'
您可以尝试使用,as suggested here:
const fromDeck = JSON.parse(JSON.stringify(this.state.sideDeck))
这应该创建一个全新的副本。
这是我的 class Content
,在 App.js
中渲染。我已通读 ReactJS 教程并了解我需要在不突变的情况下更改数据。
https://reactjs.org/tutorial/tutorial.html
但即使我使用 slice
,应用程序也不会在状态更改时重新呈现。
这 class 管理一副纸牌,如下所示:
//omitted imports
import main_deck from ...
import side_deck from ...
export default class Content extends Component {
constructor(props) {
super(props);
this.moveToMainDeck = this.moveToMainDeck.bind(this);
this.state = {
mainDeck : main_deck,
sideDeck : side_deck
}
}
moveToMainDeck(card) {
const fromDeck = this.state.sideDeck.slice(); //copy the state data
const toDeck = this.state.mainDeck.slice();
var movable = checkMovability(fromDeck, toDeck, card);
if (movable[0] === 1) { //use slice instead of splice
var newMain = toDeck.slice(0, movable[1]).concat([card]).concat(toDeck.slice(movable[1]));
var cardIndexInSideDeck = fromDeck.indexOf(card);
var newSide = fromDeck.slice(0, cardIndexInSideDeck).concat(fromDeck.slice(cardIndexInSideDeck + 1));
this.setState({ mainDeck : newMain, sideDeck : newSide });
}
else if (movable[0] === -1)
alert("Unable to move. Main Deck is full.");
else //movable[0] === 0
alert("Unable to move. Limit reached for this card in Main Deck.");
}
render() {
return (
<div><MainDeck ... /><SideDeck ... /></div>
);
}
}
使用上面的代码,我通过打印出 JSON 数组来测试状态数据,在 this.setState
之后状态确实发生了变化,但是视图仍然没有重新渲染。
但是,我通过将 slice()
替换为 push()
进行了测试,状态更改后所有内容都会重新呈现,如下所示:fromDeck.push(card);
或 toDeck.push(card);
任何人请告诉我我正在使用的 slice
有什么问题。非常感谢!
这是因为 slice 函数创建了一个浅拷贝,这意味着它只复制对象的结构,这进一步意味着不复制对象的字段,只共享引用,所以当你在复制对象中更改原始对象时对象也会改变,所以当 react 比较它发现的差异时 none 因此它不会重新渲染。
//Example
var one=[{'a':'first'},{'b':'second'}]
var two=one.slice()
var three=two.slice(0,1)
three[0].a='third'
//Now in all variables (one,two,three) a will have value of 'three'
您可以尝试使用,as suggested here:
const fromDeck = JSON.parse(JSON.stringify(this.state.sideDeck))
这应该创建一个全新的副本。