javascript - React.js における状態配列の正しい変更方法
state配列の末尾に要素を追加したいのですが、これで正しい方法でしょうか?
this.state.arrayvar.push(newelement);
this.setState({ arrayvar:this.state.arrayvar });
私は、pushで配列をその場で変更することが問題を引き起こすかもしれないと心配しています - 安全ですか?
配列のコピーを作成して、それに setState を使うという方法は無駄に思えます。
回答 #1
Reactのドキュメントには次のように書かれています:
this.stateを不変であるかのように扱いなさい。
あなたのpushは状態を直接変更するため、潜在的にエラーが発生しやすいコードにつながる可能性があります。たとえその後に状態を「リセット」してもです。例えば、一部のライフサイクルメソッドであるcomponentDidUpdateがトリガーされないことにつながるかもしれません。
後の React バージョンで推奨される方法は、状態を変更する際に競合状態を防ぐために アップデータ 関数を使用することです:
this.setState(prevState => ({
arrayvar: [...prevState.arrayvar, newelement]
}))
非標準の状態変更を使用する際に直面する可能性のあるエラーと比べると、メモリの「無駄」は問題ではありません。
以前のReactバージョン用の代替構文
新しい配列を返すので、構文をすっきりさせるために concat を使用することができます:
this.setState({
arrayvar: this.state.arrayvar.concat([newelement])
})
ES6ではスプレッド演算子を使用できます:
this.setState({
arrayvar: [...this.state.arrayvar, newelement]
})
回答 #2
もし ES6 を使っているなら、最も簡単です。
initialArray = [1, 2, 3];
newArray = [...initialArray, 4]; // --> [1,2,3,4]
新しい配列は[1,2,3,4]になります
Reactであなたの状態を更新するために
this.setState({
arrayvar: [...this.state.arrayvar, newelement]
});
配列の分割代入について詳しく学ぶ
回答 #3
ES6での最も簡単な方法:
this.setState(prevState => ({
array: [...prevState.array, newElement]
}))
回答 #4
現在、多くの人が useState フックの状態を更新する際に問題に直面しています。私はこの方法を使って安全に更新しており、ここで共有したいと思います。
これは私の状態です
const [state, setState] = useState([])
例えば、obj1という名前のオブジェクトがあって、それを自分の状態に追加したいとします。私は次のようにすることをお勧めします
setState(prevState => ([...prevState, obj1]))
これはオブジェクトを末尾に安全に挿入し、状態の一貫性も維持します
回答 #5
React は更新をまとめて行うことがあるため、正しい方法は、更新を実行する関数を setState に渡すことです。
React更新アドオンの場合、次の方法が確実に動作します:
this.setState(state => update(state, {array: {$push: [4]}}));
または concat() の場合:
this.setState(state => ({
array: state.array.concat([4])
}));
以下に示すのは、https://jsbin.com/mofekakuqi/7/edit?js,output が間違えた場合に何が起こるかの例としてのものです。
setTimeout() の呼び出しは正しく3つのアイテムを追加します。なぜなら、Reactは setTimeout コールバック内では更新をまとめて処理しないからです(参照:https://groups.google.com/d/msg/reactjs/G6pljvpTGX0/0ihYw2zK9dEJ)。
バグのある onClick は「Third」のみを追加しますが、修正されたものは期待通りに F、S、T を追加します。
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
array: []
}
setTimeout(this.addSome, 500);
}
addSome = () => {
this.setState(
update(this.state, {array: {$push: ["First"]}}));
this.setState(
update(this.state, {array: {$push: ["Second"]}}));
this.setState(
update(this.state, {array: {$push: ["Third"]}}));
};
addSomeFixed = () => {
this.setState( state =>
update(state, {array: {$push: ["F"]}}));
this.setState( state =>
update(state, {array: {$push: ["S"]}}));
this.setState( state =>
update(state, {array: {$push: ["T"]}}));
};
render() {
const list = this.state.array.map((item, i) => {
return <li key={i}>{item}</li>
});
console.log(this.state);
return (
<div className='list'>
<button onClick={this.addSome}>add three</button>
<button onClick={this.addSomeFixed}>add three (fixed)</button>
<ul>
{list}
</ul>
</div>
);
}
};
ReactDOM.render(<List />, document.getElementById('app'));
回答 #6
もしあなたが React で 関数型 コンポーネントを使用している場合
const [cars, setCars] = useState([{
name: 'Audi',
type: 'sedan'
}, {
name: 'BMW',
type: 'sedan'
}])
...
const newCar = {
name: 'Benz',
type: 'sedan'
}
const updatedCarsArray = [...cars, newCar];
setCars(updatedCarsArray);
回答 #7
コメントで@nilgunが言及したように、reactのイミュータビリティヘルパーを使用できます。私はこれが非常に役立つことを発見しました。
ドキュメントより:
簡単なプッシュ
var initialArray = [1, 2, 3];
var newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
initialArray はまだ [1, 2, 3] です。
