この記事では React.setState を使用する際に注意すべき 3 つの点を中心に紹介します。興味のある方は参考にしてください。前書き
この記事の元のタイトルは「 3 Reasons Why I stop using React.setState 」ですが、私は元の著者が提唱した議論にはあまり興味がありませんが、著者が提起した 3 つの点は無視しやすいものです。 React初心者向けの場なので、ここでは内容の一部のみを紹介し、タイトルをReact.setStateを使う際の注意点3点に変更しました。
Text
React の初心者にとって、setState の使用は非常に複雑です。 React 開発に熟練した人でも、次の例のような React の仕組みによっていくつかのバグが発生する可能性があります:
このドキュメントでは、setState を使用するときにどのような問題に注意する必要があるかについても説明しています:
注:
this.state を直接変更しないでください。後で setState() を呼び出すと、行った変更が置き換えられる可能性があります
。 this.state を不変として扱います。 setState() は this.state をすぐには変更しませんが、すぐに処理される状態遷移を作成します。このメソッドを呼び出した後に this.state にアクセスすると、既存の値が返される場合があります。 setState への呼び出しには同期の保証はなく、パフォーマンス向上のために呼び出しがバッチ化される場合があります。 setState() は、条件付きレンダリング ロジックが shouldComponentUpdate() に実装されていない限り、常に再描画をトリガーします。可変オブジェクトが使用されており、このロジックを shouldComponentUpdate() で実装できない場合は、新しい状態と前の状態に違いがある場合にのみ setState() を呼び出すことで、不必要な再レンダリングを回避できます。 要約すると、setState を使用する場合、注意すべき 3 つの問題があります:1. setState は非同期です (翻訳者注: 同期は保証されていません)
多くの開発者は、setState が非同期であることに最初は気づきませんでした。 。一部の状態を変更してからそれを直接表示すると、前の状態が表示されます。これは、setState の中で最もエラーが発生しやすい場所です。 setState という単語は非同期に見えないため、何も考えずに使用するとバグが発生する可能性があります。次の例は、この問題をよく示しています:
class Select extends React.Component { constructor(props, context) { super(props, context) this.state = { selection: props.values[0] }; } render() { return ( <ul onKeyDown={this.onKeyDown} tabIndex={0}> {this.props.values.map(value => <li className={value === this.state.selection ? 'selected' : ''} key={value} onClick={() => this.onSelect(value)} > {value} </li> )} </ul> ) } onSelect(value) { this.setState({ selection: value }) this.fireOnSelect() } onKeyDown = (e) => { const {values} = this.props const idx = values.indexOf(this.state.selection) if (e.keyCode === 38 && idx > 0) { /* up */ this.setState({ selection: values[idx - 1] }) } else if (e.keyCode === 40 && idx < values.length -1) { /* down */ this.setState({ selection: values[idx + 1] }) } this.fireOnSelect() } fireOnSelect() { if (typeof this.props.onSelect === "function") this.props.onSelect(this.state.selection) /* not what you expected..*/ } } ReactDOM.render( <Select values={["State.", "Should.", "Be.", "Synchronous."]} onSelect={value => console.log(value)} />, document.getElementById("app") )
2. setState により不要なレンダリングが発生します
setState によって引き起こされる 2 番目の問題は、呼び出しごとに再レンダリングが発生することです。多くの場合、こうした再レンダリングは不要です。 React パフォーマンス ツールで printWasted を使用すると、不必要なレンダリングがいつ発生するかを確認できます。ただし、大まかに言えば、不必要なレンダリングにはいくつかの理由があります:
新しい状態は、実際には前の状態と同じです。この問題は通常、 shouldComponentUpdate を使用して解決できます。この問題を解決するには、純粋なレンダリングまたは他のライブラリを使用することもできます。上記の最後の点に基づいて、すべてのコンポーネントの状態を setState で保存および更新する必要はありません。複雑なコンポーネントには、管理が必要なさまざまな状態がある場合があります。 setState を使用してこれらの状態を管理すると、不必要な再レンダリングが大量に発生するだけでなく、関連するライフサイクル フックが常に呼び出され、多くの奇妙な問題が発生します。
後日談
元記事では、作者はいくつかの状態を管理するためにMobXというライブラリを推奨していましたが、私はあまり寒くないので紹介しません。ご興味がございましたら、上部のリンクから元記事の紹介文をご覧ください。
上記の 3 つの点を踏まえると、初心者は次の点に注意する必要があると思います: setState は同期されることが保証されていない setState は同期されることが保証されていない、同期されることが保証されていない、同期されることが保証されていない同期されること。大事なことは3回言いましょう。非同期とは言えない理由は、setState も同期的に更新される場合があるためです。 この記事を参照してください setState の直後に変更された値を取得する必要がある場合は、いくつかのオプションがあります: this.state を通じて取得せず、対応するパラメータを渡します针对于之前的例子,完全可以在调用 fireOnSelect 的时候,传入需要的值。而不是在方法中在通过 this.state 来获取
使用回调函数
setState 方法接收一个 function 作为回调函数。这个回掉函数会在 setState 完成以后直接调用,这样就可以获取最新的 state 。对于之前的例子,就可以这样:
this.setState({ selection: value }, this.fireOnSelect)
使用setTimeout
在 setState 使用 setTimeout 来让 setState 先完成以后再执行里面内容。这样子:
this.setState({ selection: value }); setTimeout(this.fireOnSelect, 0);
直接输出,回调函数, setTimeout 对比
componentDidMount(){ this.setState({val: this.state.val + 1}, ()=>{ console.log("In callback " + this.state.val); }); console.log("Direct call " + this.state.val); setTimeout(()=>{ console.log("begin of setTimeout" + this.state.val); this.setState({val: this.state.val + 1}, ()=>{ console.log("setTimeout setState callback " + this.state.val); }); setTimeout(()=>{ console.log("setTimeout of settimeout " + this.state.val); }, 0); console.log("end of setTimeout " + this.state.val); }, 0); }
如果val默认为0, 输入的结果是:
Direct call 0
In callback 1
begin of setTimeout 1
setTimeout setState callback 2
end of setTimeout 2
setTimeout of settimeout 2
和渲染无关的状态尽量不要放在 state 中来管理
通常 state 中只来管理和渲染有关的状态 ,从而保证 setState 改变的状态都是和渲染有关的状态。这样子就可以避免不必要的重复渲染。其他和渲染无关的状态,可以直接以属性的形式保存在组件中,在需要的时候调用和改变,不会造成渲染。
避免不必要的修改,当 state 的值没有发生改变的时候,尽量不要使用 setState 。虽然 shouldComponentUpdate 和 PureComponent 可以避免不必要的重复渲染,但是还是增加了一层 shallowEqual 的调用,造成多余的浪费。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がReact.setStateを使用する際に注意すべき点は何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。