it-swarm.com.de

Können Sie das Reagieren einer React-Komponente erzwingen, ohne setState aufzurufen?

Ich habe ein externes (an der Komponente) beobachtbares Objekt, auf das ich Änderungen überprüfen möchte. Wenn das Objekt aktualisiert wird, gibt es Änderungsereignisse aus. Ich möchte die Komponente dann erneut rendern, wenn eine Änderung erkannt wird.

Mit einem React.render der obersten Ebene war dies möglich, aber innerhalb einer Komponente funktioniert es nicht (was sinnvoll ist, da die render-Methode nur ein Objekt zurückgibt).

Hier ist ein Codebeispiel:

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>
    )
  }
}

Wenn Sie auf die Schaltfläche klicken, wird intern this.render() aufgerufen. Dies ist jedoch nicht der Grund dafür, dass das Rendering tatsächlich ausgeführt wird (Sie können dies in Aktion sehen, da sich der von {Math.random()} erstellte Text nicht ändert). Wenn ich jedoch einfach this.setState() anstelle von this.render() anrufe, funktioniert es einwandfrei.

Ich denke, meine Frage ist: Reagieren Sie die Komponenten need, um einen Zustand zu haben, um neu zu rendern? Gibt es eine Möglichkeit, die Aktualisierung der Komponente bei Bedarf zu erzwingen, ohne den Status zu ändern?

462
Philip Walton

In Ihrer Komponente können Sie this.forceUpdate() aufrufen, um einen Wiederholer zu erzwingen. 

Dokumentation: https://facebook.github.io/react/docs/component-api.html

566
Crob

forceUpdate sollte vermieden werden, da es von einer Denkweise von React abweicht. Die React-Dokumente zitieren ein Beispiel, wann forceUpdate verwendet werden könnte:

Wenn sich der Status oder die Requisiten Ihrer Komponente ändern, wird sie standardmäßig erneut gerendert. Wenn sich diese jedoch implizit ändern (z. B. Daten tief in einem Objekt ändern, ohne das Objekt selbst zu ändern) oder wenn Ihre render () - Methode von anderen Daten abhängig ist, können Sie React mitteilen, dass es render () erneut ausführen muss, indem Sie es aufrufen Update erzwingen().

Ich möchte jedoch die Idee vorschlagen, dass forceUpdate selbst bei tief verschachtelten Objekten nicht erforderlich ist. Durch die Verwendung einer unveränderlichen Datenquelle wird das Nachverfolgen von Änderungen billig. Eine Änderung führt immer zu einem neuen Objekt. Wir müssen also nur prüfen, ob sich die Referenz auf das Objekt geändert hat. Sie können die Bibliothek Immutable JS verwenden, um unveränderliche Datenobjekte in Ihre App zu implementieren.

Normalerweise sollten Sie versuchen, alle Verwendungen von forceUpdate () zu vermeiden und nur von this.props und this.state in render () zu lesen. Dadurch wird Ihre Komponente "rein" und Ihre Anwendung wesentlich einfacher und effizienter. https://facebook.github.io/react/docs/component-api.html#forceupdate

Das Ändern des Schlüssels des neu gerenderten Elements wird funktionieren. Legen Sie die Schlüsselstütze für Ihr Element über state fest und dann, wenn Sie den set state aktualisieren möchten, um einen neuen Schlüssel zu erhalten. 

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

Dann tritt eine Änderung ein und Sie setzen den Schlüssel zurück

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

Ich möchte darauf hinweisen, dass dies das Element ersetzt, an dem der Schlüssel geändert wird. Ein Beispiel, wo dies nützlich sein könnte, ist ein Dateieingabefeld, das Sie nach dem Hochladen eines Bildes zurücksetzen möchten. 

Die wahre Antwort auf die Frage des OP wäre forceUpdate(). Ich habe diese Lösung in verschiedenen Situationen als hilfreich empfunden. Ich möchte auch beachten, dass Sie, wenn Sie forceUpdate verwenden, Ihren Code überprüfen und prüfen möchten, ob es einen anderen Weg gibt, Dinge zu tun.

HINWEIS 1-9-2019: 

Das obige (Ändern des Schlüssels) ersetzt das Element vollständig. Wenn Sie feststellen, dass Sie den Schlüssel aktualisieren, um Änderungen vorzunehmen, liegt möglicherweise ein Problem an anderer Stelle in Ihrem Code vor. Durch Verwendung von Math.random() in key wird das Element bei jedem Rendern neu erstellt. Ich würde NICHT das Aktualisieren des Schlüssels empfehlen, da rea ​​den Schlüssel verwendet, um die beste Methode zum erneuten Rendern zu ermitteln.

249
pizza-r0b

Tatsächlich ist forceUpdate() die einzig richtige Lösung, da setState()not ein erneutes Rendern auslösen kann, wenn zusätzliche Logik in shouldComponentUpdate() implementiert ist oder einfach false zurückgegeben wird.

update erzwingen()

Wenn Sie forceUpdate() aufrufen, wird render() für die Komponente aufgerufen, wobei shouldComponentUpdate() übersprungen wird. Mehr...

setState ()

setState() löst immer ein Re-Rendering aus, sofern in shouldComponentUpdate() keine bedingte Rendering-Logik implementiert ist. Mehr...


forceUpdate() kann innerhalb Ihrer Komponente von this.forceUpdate() aufgerufen werden.

50
Qwerty

Wenn zwei React-Komponenten kommunizieren sollen, die nicht an eine Beziehung gebunden sind (Parent-Child), empfiehlt es sich, Flux oder ähnliche Architekturen zu verwenden. 

Was Sie tun möchten, ist, auf Änderungen der beobachtbare Komponente store, der das Modell und seine Schnittstelle enthält, und das Speichern der Daten, die bewirken, dass sich der Render ändert, als state in MyComponent. Wenn der Store die neuen Daten überträgt, ändern Sie den Status Ihrer Komponente, wodurch das Rendern automatisch ausgelöst wird.

Normalerweise sollten Sie versuchen, die Verwendung von forceUpdate() zu vermeiden. Aus der Dokumentation:

Normalerweise sollten Sie versuchen, alle Verwendungen von forceUpdate () zu vermeiden und nur von this.props und this.state in render () zu lesen. Dies macht Ihre Anwendung wesentlich einfacher und effizienter

28
gcedo

Ich habe forceUpdate vermieden, indem ich Folgendes getan habe

FALSCHER WEG : Verwenden Sie keinen Index als Schlüssel

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

CORRECT WAY : Verwenden Sie die Daten-ID als Schlüssel

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

durch eine solche Code-Verbesserung wird Ihre KomponenteUNIQUEnatürlich gerendert

24
vijay

Ich denke also, meine Frage ist: Reagieren Komponenten müssen einen Zustand in .__ haben. um zu rendern? Gibt es eine Möglichkeit, die Aktualisierung der Komponente auf .__ zu erzwingen. Nachfrage ohne den Staat zu wechseln?

Die anderen Antworten haben versucht zu veranschaulichen, wie Sie könnten, aber der Punkt ist: Sie sollten nicht . Selbst die abgefahrene Lösung, den Schlüssel zu wechseln, verfehlt den Punkt. Die Macht von React gibt die Kontrolle über die manuelle Verwaltung auf, wenn etwas gerendert werden soll, und kümmert sich stattdessen nur darum, wie etwas auf Eingaben abgebildet werden soll. Dann liefern Sie den Strom der Eingänge.

Wenn Sie das erneute Rendern manuell erzwingen müssen, machen Sie fast sicher nichts richtig.

11
Kyle Baker

Keine ernsten Renderzustände des Staates

Ich habe meine Daten viel im Status gespeichert, als ich mit reag angefangen habe und dachte, ich müsste das für das Rendern tun. Das war sehr falsch. Es stellt sich heraus, Sie können sogar komplizierte Dinge wie Flux und Redux vermeiden, wenn Sie einige einfache unveränderliche Läden rollen.

BaseView -Klasse zum Erben von und zur Verarbeitung von Geschäftsaktualisierungen

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)
    })
  }

}

Wie benutzt man

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>)
  }
}

Einfaches Beispiel für die Klasse 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)
  }
}

Instanz als Singleton speichern

import Store from './Store'

const myStore = new Store()
export default myStore

Ich denke, dadurch werden alle cruftigen Frameworks für kleinere Apps aufgehoben. Verwenden Sie redux für mittlere bis große, wenn auch mit Immutable.js.

update Sie sollten sich die neuesten Entwicklungen von "Hooks" in React ansehen. Das scheint sehr sauber und minimal zu sein. 

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

8
Jason Sebring

Sie können es auf zwei Arten tun:

1. Verwenden Sie die forceUpdate()-Methode:

Bei Verwendung der forceUpdate()-Methode können einige Störungen auftreten. Ein Beispiel ist, dass die shouldComponentUpdate()-Methode ignoriert wird und die Ansicht erneut gerendert wird, unabhängig davon, ob shouldComponentUpdate() false zurückgibt. Aus diesem Grund sollte forceUpdate () möglichst vermieden werden.

2. Übergeben von this.state an die setState()-Methode

Die folgende Codezeile behebt das Problem mit dem vorherigen Beispiel:

this.setState(this.state);

Tatsächlich wird dabei nur der aktuelle Status mit dem aktuellen Status überschrieben, der ein erneutes Rendering auslöst. Dies ist zwar immer noch nicht unbedingt der beste Weg, um einige Dinge zu beheben, die mit der forceUpdate () -Methode auftreten könnten.

3
kojow7

Wir können this.forceUpdate () wie folgt verwenden.

       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);

Der Elementteil 'Math.random' im DOM wird nur dann aktualisiert, wenn Sie die Komponente mit setState erneut rendern.

Alle Antworten hier sind richtig und ergänzen die Frage zum Verständnis. Wie Sie wissen, ist das Rendern einer Komponente ohne setState ({}) mit forceUpdate ().

Der obige Code wird mit setState wie folgt ausgeführt.

 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

Um das auszuführen, was Sie beschreiben, versuchen Sie es mit this.forceUpdate ().

0
API-Andy

forceUpdate();-Methode wird funktionieren, es ist jedoch ratsam, setState(); zu verwenden.

0

Ich habe es am besten gefunden, forceUpdate () zu vermeiden. Eine Möglichkeit, das erneute Rendern zu erzwingen, besteht darin, Abhängigkeit von render () von einer temporären externen Variablen hinzuzufügen und den Wert dieser Variablen bei Bedarf zu ändern. 

Hier ist ein Codebeispiel:

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>
      )
   }
}

Rufen Sie this.forceChange () auf, wenn Sie das erneute Rendern erzwingen möchten.

0
raksheetbhat

ES6 - Ich füge ein Beispiel hinzu, das für mich hilfreich war:

In einer "kurzen if-Anweisung" können Sie eine leere Funktion wie folgt übergeben:

isReady ? ()=>{} : onClick

Dies scheint der kürzeste Weg zu sein.

()=>{}
0
MrDoda

Noch eine Antwort, um die akzeptierte Antwort zu sichern :-)

React entmutigt die Verwendung von forceUpdate(), da sie in der Regel einen sehr "einfachen Weg" zur funktionalen Programmierung haben. Dies ist in vielen Fällen in Ordnung, aber viele React-Entwickler verfügen über einen OO-Hintergrund. Mit diesem Ansatz ist es absolut in Ordnung, ein beobachtbares Objekt zu hören.

Wenn dies der Fall ist, wissen Sie wahrscheinlich, dass Sie erneut MÜSSEN müssen, wenn das Beobachtbare "feuert", und wenn Sie dies tun, SOLLTEN Sie forceUpdate() verwenden, und es ist tatsächlich ein Plus, dass shouldComponentUpdate() hier NICHT beteiligt ist. 

Werkzeuge wie MobX, die einen OO-Ansatz verfolgen, tun dies tatsächlich unter der Oberfläche (tatsächlich ruft MobX render() direkt auf).

0
Plaul

Es gibt verschiedene Möglichkeiten, Ihre Komponente erneut zu rendern:

Die einfachste Lösung ist die Verwendung der forceUpdate () -Methode:

this.forceUpdate()

Eine weitere Lösung besteht darin, einen nicht verwendeten Schlüssel im Status (nonUsedKey) zu erstellen und die Funktion setState mit der Aktualisierung dieses nonUsedKey aufzurufen:

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

Oder schreiben Sie den aktuellen Status neu:

this.setState(this.state);

Das Ändern von Requisiten bietet auch die Möglichkeit, Komponenten neu zu rendern.

0
Jackkobec

Eine andere Möglichkeit ist, setState, UND preserve state aufzurufen:

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

0
dbvt10

forceUpdate (), aber jedes Mal, wenn ich jemanden darüber sprechen hörte, wurde nachverfolgt, dass Sie dies niemals verwenden sollten.

0
Ian

Sie können forceUpdate () verwenden, um weitere Details zu überprüfen ( forceUpdate () ).

0
Harshit Singhai