web-dev-qa-db-ja.com

SetStateを呼び出さずにReactコンポーネントにレンダリングを強制することはできますか?

変更を監視したい(コンポーネントに対して)外部の、観察可能なオブジェクトがあります。オブジェクトが更新されると、それはchangeイベントを発行します。そして、何らかの変更が検出されたときにコンポーネントをレンダリングしたいのです。

トップレベルのReact.renderではこれは可能でしたが、コンポーネント内では機能しません(renderメソッドはオブジェクトを返すだけなのである程度意味があります)。

これがコード例です。

export default class MyComponent extends React.Component {

  handleButtonClick() {
    this.render();
  }

  render() {
    return (
      <div>
        {Math.random()}
        <button onClick={this.handleButtonClick.bind(this)}>
          Click me
        </button>
      </div>
    )
  }
}

ボタンをクリックすると内部的にthis.render()が呼び出されますが、実際にレンダリングが行われるわけではありません({Math.random()}によって作成されたテキストは変更されないので、実際にこれを見ることができます)。しかし、this.setState()の代わりにthis.render()を呼び出しただけでは、うまくいきます。

だから私は私の質問だと思います: Reactコンポーネント 必要 表示し直すために状態を保持するには?状態を変更せずにコンポーネントをオンデマンドで更新するように強制する方法はありますか?

508
Philip Walton

あなたのコンポーネントの中で、this.forceUpdate()を呼び出して強制的に再表示することができます。 

ドキュメント: https://facebook.github.io/react/docs/component-api.html

566
Crob

forceUpdateはReactの考え方から逸脱しているので避けるべきです。 ReactのドキュメントはforceUpdateが使われるかもしれないときの例を挙げています:

デフォルトでは、コンポーネントの状態や小道具が変わると、コンポーネントは再レンダリングされます。しかし、これらが暗黙のうちに変更された場合(例:オブジェクト自体を変更せずにオブジェクト内の深いデータが変更された場合)、またはrender()メソッドが他のデータに依存する場合、アップデートさせる()。

しかし、深くネストされたオブジェクトでもforceUpdateは不要であるという考えを提案したいと思います。不変のデータソースを使用することで、変更の追跡は安価になります。変更は常に新しいオブジェクトになるため、オブジェクトへの参照が変更されたかどうかを確認するだけで済みます。不変データオブジェクトをアプリに実装するには、ライブラリ 不変JS を使用します。

通常、forceUpdate()の使用をすべて避け、render()のthis.propsとthis.stateからのみ読み取るようにしてください。これはあなたのコンポーネントを「純粋に」し、そしてあなたのアプリケーションをずっと簡単にそしてもっと効率的にする。 https://facebook.github.io/react/docs/component-api.html#forceupdate

再レンダリングしたい要素のキーを変更するとうまくいきます。 stateを介してあなたの要素にkey propを設定し、それからあなたが新しいkeyを持つようにset stateを更新したい時。 

<Element key={this.state.key} /> 

その後、変更が発生してキーをリセットします

this.setState({ key: Math.random() });

これは、キーが変更されている要素を置き換えることになります。これが役立つ可能性がある場所の例は、画像のアップロード後にリセットしたいファイル入力フィールドがある場合です。 

OPの質問に対する真の答えはforceUpdate()ですが、私はこの解決策がさまざまな状況で役立つことを見出しました。自分がforceUpdateを使っているのに気づいたら、自分のコードを見直して別の方法があるかどうかを確認したいと思うかもしれません。

NOTE 1-9-2019:  

上記(キーの変更)は要素を完全に置き換えます。自分でキーを更新して変更を加えることがわかった場合は、おそらくコードのどこかに問題があるでしょう。 keyでMath.random()を使用すると、レンダリングごとに要素が再作成されます。 reactはキーを使用してものを再レンダリングする最善の方法を決定するので、このようにキーを更新することはお勧めしません。

249
pizza-r0b

2つのReactコンポーネントが通信(親子)に束縛されないように通信したい場合は、 Flux または同様のアーキテクチャを使用することをお勧めします。 

あなたがしたいのはの変化を聞くことです 観測可能成分 モデルとそのインターフェースを保持し、レンダリングを変更させるデータをstateMyComponentとして保存します。ストアが新しいデータをプッシュすると、コンポーネントの状態が変わり、自動的にレンダリングが開始されます。

通常はforceUpdate()を使わないようにするべきです。ドキュメントから:

通常、forceUpdate()の使用をすべて避け、render()のthis.propsとthis.stateからのみ読み取るようにしてください。これによりあなたのアプリケーションはずっとシンプルで効率的になります。

28
gcedo

私は次のようにしてforceUpdateを避けました

間違った方法 :キーとしてインデックスを使用しない

this.state.rows.map((item, index) =>
   <MyComponent cell={item} key={index} />
)

正しい方法 :データIDをキーとして使う

this.state.rows.map((item) =>
   <MyComponent item={item} key={item.id} />
)

そのようなコード改善をすることによってあなたのコンポーネントは _ unique _ になり自然にレンダリングされます

24
vijay

だから私は私の質問だと思います:Reactのコンポーネントはで表現する必要がありますか?状態を変えずにオンデマンドでコンポーネントを強制的に更新する方法はありますか?

他の答えはあなたがどうやってできるかを説明しようとしました、しかし、ポイントは あなたはそうするべきではありません です。キーを変更するという厄介な解決策でさえ、その点を見逃しています。 Reactの力は、何かをいつレンダリングすべきかを手動で管理することのコントロールを放棄することであり、その代わりに、何かが入力にどのようにマッピングされるべきかについての自分自身に関するものです。それから入力の流れを供給しなさい。

手動で強制的に再レン​​ダリングする必要がある場合、ほぼ確実に正しいことはしていません。

11
Kyle Baker

再レンダリングを心配する州はありません

私は私がレンダリングのためにこれをしなければならなかったと思って反応を使い始めたとき私は私のデータを多くの状態で保存していました。それはとても間違っていました。結局のところ、単純な不変ストアをロールバックすれば、FluxやReduxのような複雑なことをやることさえ避けることができます。

ストアの更新を継承し、ストアの更新を処理するBaseViewクラス

import React, { Component } from 'react';
import { View } from 'react-native';

export default class BaseView extends Component {

  constructor(props) {
    super(props)
    this.state = {}
  }

  onChange = () => {
    this.setState(this.state) // dumb easy: triggers render
  }

  componentWillMount = () => {
    this.stores && this.stores.forEach(store => {
      // each store has a common change event to subscribe to
      store.on('change', this.onChange)
    })
  }

  componentWillUnmount = () => {
    this.stores && this.stores.forEach(store => {
      store.off('change', this.onChange)
    })
  }

}

使い方

import React, { Component } from 'react'
import { View, Text } from 'react-native'
import BaseView from './BaseView'
import myStore from './myStore'

class MyView extends BaseView {
  contructor(props) {
    super(props)
    this.stores = [myStore]
  }

  render() {
    return (<View><Text onPress={() => {
      myStore.update({ message: 'hi' + Date.now() })
    }}>{myStore.get().message}</Text></View>)
  }
}

単純なStoreクラスの例

var ee = require('event-emitter')
export default class Store {
  constructor() {
    this._data = {}
    this._eventEmitter = ee({})
  }
  get() {
    return {...this._data} // immutable
  }
  update(newData) {
    this._data = {...this._data, ...newData}
    this._eventEmitter.emit('change')
  }
  on(ev, fn) {
    this._eventEmitter.on(ev, fn)
  }
  off(ev, fn) {
    this._eventEmitter.off(ev, fn)
  }
}

シングルトンとしてのストアインスタンス

import Store from './Store'

const myStore = new Store()
export default myStore

これは、小規模なアプリケーションに必要なすべての重要なフレームワークを廃止すると思います。 Immutable.jsと組み合わせることで、中規模から大規模のものにreduxを使用できます。

update Reactの最近の "hooks"の開発について調べてください。これは本当にきれいで最小限のようです。 

https://reactjs.org/docs/hooks-intro.html

8
Jason Sebring

いくつかの方法があります。

1. forceUpdate()メソッドを使用します。

forceUpdate()メソッドを使用するときに起こるかもしれないいくつかの不具合があります。一例として、shouldComponentUpdate()メソッドが無視され、shouldComponentUpdate()がfalseを返すかどうかにかかわらず、ビューが再レンダリングされます。このため、forceUpdate()の使用は可能な限り回避する必要があります。

2. this.stateをsetState()メソッドに渡す

次のコード行は、前の例の問題を解決します。

this.setState(this.state);

実際にこれがしているのは、現在の状態を現在の状態で上書きして再レンダリングをトリガーすることだけです。これは必ずしも最善の方法ではありませんが、forceUpdate()メソッドを使用したときに発生する可能性がある問題のいくつかを解決します。

3
kojow7

以下のようにthis.forceUpdate()を使うことができます。

       class MyComponent extends React.Component {



      handleButtonClick = ()=>{
          this.forceUpdate();
     }


 render() {

   return (
     <div>
      {Math.random()}
        <button  onClick={this.handleButtonClick}>
        Click me
        </button>
     </div>
    )
  }
}

 ReactDOM.render(<MyComponent /> , mountNode);

DOMの要素 'Math.random'部分は、setStateを使用してコンポーネントを再レンダリングした場合でも更新されるだけです。

SetState({})を使わずにコンポーネントを再レンダリングするのはforceUpdate()を使うことです。

上記のコードは以下のようにsetStateで実行されます。

 class MyComponent extends React.Component {



             handleButtonClick = ()=>{
                this.setState({ });
              }


        render() {
         return (
  <div>
    {Math.random()}
    <button  onClick={this.handleButtonClick}>
      Click me
    </button>
  </div>
)
  }
 }

ReactDOM.render(<MyComponent /> , mountNode);
2
Dhana

受け入れられた答えをバックアップするための別の返信:-)

Reactは、一般に関数型プログラミングに対して非常に「これが唯一の方法」アプローチであるため、forceUpdate()の使用を推奨していません。多くの場合これで問題ありませんが、多くのReact開発者はオブジェクト指向の背景を持っており、そのアプローチを使えば、監視可能なオブジェクトを聞くことはまったく問題ありません。

そして、もしあなたがそうするなら、おそらく観測可能なものが「発火」したときに再レンダリングしなければならないことを知っているので、forceUpdate()を使用すべきであり、実際にはshouldComponentUpdate()はここに含まれません。

オブジェクト指向のアプローチをとるMobXのようなツールは、実際に表面下でこれを行っています(実際には、MobXはrender()を直接呼び出します)

1
Plaul

説明していることを達成するために、this.forceUpdate()を試してください。

0
API-Andy

forceUpdate();メソッドは機能しますが、setState();を使用することをお勧めします。

0

ForceUpdate()を回避するのが最善の方法です。再レンダリングを強制する1つの方法は、一時的な外部変数にrender()の依存関係を追加し、必要に応じてその変数の値を変更することです。 

これがコード例です。

class Example extends Component{
   constructor(props){
      this.state = {temp:0};

      this.forceChange = this.forceChange.bind(this);
   }

   forceChange(){
      this.setState(prevState => ({
          temp: prevState.temp++
      })); 
   }

   render(){
      return(
         <div>{this.state.temp &&
             <div>
                  ... add code here ...
             </div>}
         </div>
      )
   }
}

強制的に再レン​​ダリングする必要がある場合は、this.forceChange()を呼び出してください。

0
raksheetbhat

ES6 - 私は参考になった例を含めています。

「短いif文」では、次のように空の関数を渡すことができます。

isReady ? ()=>{} : onClick

これが最短の方法です。

()=>{}
0
MrDoda

コンポーネントをレンダリングする方法はいくつかあります。

最も簡単な解決策は、forceUpdate()メソッドを使用することです。

this.forceUpdate()

もう1つの解決策は、未使用状態のキー(nonUsedKey)を作成し、このnonUsedKeyを更新してsetState関数を呼び出すことです。

this.setState({ nonUsedKey: Date.now() } );

または現在の状態をすべて書き換えます。

this.setState(this.state);

小道具の変更はまたコンポーネントのレンダリングを提供します。

0
Jackkobec

別の方法はsetState _、および_ preserve stateを呼び出すことです。 

this.setState(prevState=>({...prevState}));

0
dbvt10

forceUpdate()が、誰かがそれについて話すのを聞いたことがあるたびに、これを使用しないでください。

0
Ian

詳細の確認にはforceUpdate()を使用できます( forceUpdate() )。

0
Harshit Singhai