[解決済み] Reactコンポーネントを強制的に再マウントするには?
質問
条件付きレンダーを持つビューコンポーネントがあるとします。
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
MyInputはこのような感じです。
class MyInput extends React.Component {
...
render(){
return (
<div>
<input name={this.props.name}
ref="input"
type="text"
value={this.props.value || null}
onBlur={this.handleBlur.bind(this)}
onChange={this.handleTyping.bind(this)} />
</div>
);
}
}
例えば
employed
が true であるとします。これを false に切り替えて他のビューをレンダリングすると、常に
unemployment-duration
だけが再初期化されます。また
unemployment-reason
からの値でプリフィルされます。
job-title
(の値で埋められる(条件が変わる前に値が与えられていた場合)。
2番目のレンダリングルーチンのマークアップを次のように変更すると。
render(){
if (this.state.employed) {
return (
<div>
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<span>Diff me!</span>
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
すべて正常に動作しているように見えます。Reactが'job-title'と'unemployment-reason'のdiffに失敗しているだけのように見えますが。
何が間違っているのか教えてください...。
どのように解決するのですか?
おそらく起こっていることは、Reactが1つだけの
MyInput
(
unemployment-duration
)がレンダリングの間に追加されます。そのため
job-title
に置き換えられることはありません。
unemployment-reason
に置き換えられることはなく、それが定義済みの値が入れ替わる理由でもあります。
React が diff を実行するとき、どのコンポーネントが新しく、どのコンポーネントが古いかをその
key
プロパティに基づいて、新しいコンポーネントと古いコンポーネントを決定します。そのようなキーがコードで提供されていない場合、独自に生成されます。
提供された最後のコードスニペットが機能する理由は、React が本質的に親
div
の下にあるすべての要素の階層を変更する必要があり、それがすべての子の再レンダリングをトリガーすると思うからです (これが動作する理由です)。もしあなたが
span
を追加していた場合、前の要素の階層は変更されず、それらの要素は再レンダリングされません (そして問題は解決されません)。
以下は、公式の React ドキュメント に書いてあります。
子要素が入れ替わる場合 (検索結果の場合)、または新しいコンポーネントがリストの先頭に追加される場合 (ストリームの場合) は、状況がさらに複雑になります。レンダー パスにまたがって各子供の ID と状態を維持する必要があるこれらのケースでは、キーを割り当てることにより、各子供を一意に識別できます。
React がキーを持つ子を調整するとき、キーを持つ子は (クローバーではなく) 並べ替えられるか、(再利用ではなく) 破棄されることを確認します。
これを解決するには、一意の
key
要素に、親要素である
div
またはすべての
MyInput
要素に適用されます。
例えば
render(){
if (this.state.employed) {
return (
<div key="employed">
<MyInput ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div key="notEmployed">
<MyInput ref="unemployment-reason" name="unemployment-reason" />
<MyInput ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
または
render(){
if (this.state.employed) {
return (
<div>
<MyInput key="title" ref="job-title" name="job-title" />
</div>
);
} else {
return (
<div>
<MyInput key="reason" ref="unemployment-reason" name="unemployment-reason" />
<MyInput key="duration" ref="unemployment-duration" name="unemployment-duration" />
</div>
);
}
}
これで、Reactがdiffを実行すると
divs
が異なることを認識し、すべての子要素を含めて再レンダリングします (最初の例)。2 番目の例では、差分が成功すると
job-title
と
unemployment-reason
は異なるキーを持つようになったので
もちろん、一意であればどんなキーでも使うことができます。
2017年8月更新
Reactでキーがどのように機能するかについてのより良い洞察のために、私は強く私の答えを読むことをお勧めします。 React.jsのユニークキーを理解する .
2017年11月更新
このアップデートは少し前に投稿されたはずなのですが、文字列リテラルを使って
ref
での文字列リテラル使用は非推奨となりました。例えば
ref="job-title"
は、代わりに
ref={(el) => this.jobTitleRef = el}
(のようになります(例)。に対する私の回答を参照してください。
this.refsを使用した非推奨の警告
を参照してください。
関連
-
vue ディレクティブ v-html と v-text
-
[解決済み] 期待される代入または関数呼び出し: 未使用式なし ReactJS
-
[解決済み] 配列から特定の項目を削除するにはどうすればよいですか?
-
[解決済み] jQueryで要素が非表示になっているかどうかを確認するには?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] GUID / UUIDの作成方法
-
[解決済み] React JSX内のループ
-
[解決済み】別のウェブページにリダイレクトするにはどうすればいいですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Vueの要素ツリーコントロールに破線を追加する説明
-
JSアレイループと効率解析の比較
-
JavaScriptのクロージャの説明
-
vueはopenlayersを使用してスカイマップとガオードマップをロードする
-
vueの補間表現とv-textディレクティブの違いについて
-
[解決済み】"フォームが接続されていないため、フォームの送信がキャンセルされました "というエラーの取得について
-
[解決済み】 env: node: macにそのようなファイルやディレクトリはありません
-
[解決済み】「.addEventListener is not a function」なぜこのエラーが発生するのか?
-
[解決済み】React.jsの配列の子要素のユニークキーを理解する
-
フロントエンド非同期(アシンク)ソリューション(全ソリューション)