webentwicklung-frage-antwort-db.com.de

Woher weiß eine mit Redux verbundene Komponente, wann sie wiedergegeben werden muss?

Ich vermisse wahrscheinlich etwas sehr offensichtliches und würde mich gerne klarer machen. 

Hier ist mein Verständnis.
In einer naiven Reaktionskomponente haben wir states & props. Durch die Aktualisierung von state mit setState wird die gesamte Komponente erneut dargestellt. props sind meist nur lesbar und ihre Aktualisierung ist nicht sinnvoll. 

In einer React-Komponente, die einen Redux-Store über etwas wie store.subscribe(render) abonniert, wird sie bei jeder Aktualisierung des Stores offensichtlich erneut gerendert. 

react-redux hat einen Helfer connect(), der einen Teil des Zustandsbaums (der für die Komponente von Interesse ist) und actionCreators als props in die Komponente einfügt, normalerweise über etwas Ähnliches 

const TodoListComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

Aber mit dem Verständnis, dass eine setState essentiell ist, damit TodoListComponent auf die Änderung des Redux-Zustandsbaums reagiert (erneutes Rendern), kann ich keinen state- oder setState-Code in der TodoList-Komponentendatei finden. Es liest sich ungefähr so:

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

Kann mir jemand in die richtige Richtung weisen, was mir fehlt?

P.S Ich folge dem Beispiel-ToDo-Listenpaket, das mit dem Redux-Paket gebündelt ist ( https://github.com/reactjs/redux/tree/master/examples/todos/src/containers ).

41
Joe Lewis

Die Funktion connect generiert eine Wrapper-Komponente, die den Store abonniert. Wenn eine Aktion ausgelöst wird, wird der Callback der Wrapper-Komponente benachrichtigt. Dann führt es Ihre mapState-Funktion aus, und shallow-compare das Ergebnisobjekt aus dieser Zeit mit dem Ergebnisobjekt aus der letzten Zeit (wenn Sie also umschreiben es würde kein erneutes Rendern auslösen). Wenn die Ergebnisse unterschiedlich sind, werden die Ergebnisse als Requisiten an Ihre "echte" Komponente übergeben.

Dan Abramov hat eine große vereinfachte Version von connect unter https://Gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e geschrieben, die die Grundidee veranschaulicht, obwohl sie keine Optimierungsarbeit zeigt. Ich habe auch Links zu einer Reihe von Artikeln über Redux Performance , die einige verwandte Ideen diskutieren.

update

React-Redux v6.0.0 hat einige wichtige interne Änderungen vorgenommen, wie verbundene Komponenten ihre Daten aus dem Geschäft erhalten.

Als Teil davon schrieb ich einen Beitrag, in dem erklärt wird, wie die connect-API und ihre Interna funktionieren und wie sie sich im Laufe der Zeit verändert haben:

Idiomatic Redux: Die Geschichte und Implementierung von React-Redux

63
markerikson

Meine Antwort ist etwas außerhalb des linken Feldes. Es beleuchtet ein Problem, das mich zu diesem Beitrag geführt hat. In meinem Fall schien es, als würde die App nicht erneut gerendert, obwohl sie neue Requisiten erhielt.
React-Entwickler hatten eine Antwort auf diese oft gestellte Frage: Wenn der (Speicher) mutiert ist, werden 99% der Fälle aus diesem Grund nicht mehr gerendert . Dennoch nichts über den anderen 1%. Mutation war hier nicht der Fall.


TLDR;

Mit componentWillReceiveProps kann die state mit der neuen props synchron gehalten werden.

Edge Case: Sobald state aktualisiert wurde, dann die App tut erneut rendern!


Es stellt sich heraus, dass, wenn Ihre App nur state zur Anzeige ihrer Elemente verwendet, props eine Aktualisierung durchführen kann, state jedoch nicht, also kein erneutes Rendern.

Ich hatte state, das von props abhängig war, das von redux store erhalten wurde. Die Daten, die ich brauchte, waren noch nicht im Laden, also habe ich sie von componentDidMount abgerufen, wie es sich gehört. Ich habe die Requisiten zurückbekommen, als mein Reduzierer den Speicher aktualisiert hat, da meine Komponente über mapStateToProps verbunden ist. Die Seite wurde jedoch nicht gerendert, und state war immer noch voll mit leeren Zeichenfolgen.

Ein Beispiel dafür ist, dass ein Benutzer eine Seite zum Bearbeiten von Beiträgen von einer gespeicherten URL geladen hat. Sie haben Zugriff auf die Variable postId von der URL, aber die Informationen sind noch nicht in store enthalten, also rufen Sie sie ab. Die Elemente auf Ihrer Seite sind kontrollierte Komponenten - alle Daten, die Sie anzeigen, befinden sich in state.

Mit redux wurden die Daten abgerufen, der Speicher wurde aktualisiert und die Komponente ist connected, aber die App hat die Änderungen nicht übernommen. Bei näherer Betrachtung wurde props empfangen, die App wurde jedoch nicht aktualisiert. state wurde nicht aktualisiert.

Nun, props wird aktualisiert und verbreitet, aber state wird nicht . Sie müssen state ausdrücklich mitteilen, dass sie aktualisieren soll. 

In render() ist dies nicht möglich, und componentDidMount hat bereits seine Zyklen beendet.

In componentWillReceiveProps aktualisieren Sie state-Eigenschaften, die von einem geänderten prop-Wert abhängen.

Verwendungsbeispiel:

componentWillReceiveProps(nextProps){
  if (this.props.post.category !== nextProps.post.category){
    this.setState({
      title: nextProps.post.title,
      body: nextProps.post.body,
      category: nextProps.post.category,
    })
  }      
}

Ich muss diesem Artikel einen Hinweis geben, der mich über die Lösung aufgeklärt hat, die Dutzende anderer Posts, Blogs und Repos nicht erwähnt haben. Jeder andere, der Schwierigkeiten hatte, eine Antwort auf dieses offenkundig obskure Problem zu finden, ist hier:

Lebenszyklusmethoden von ReactJs-Komponenten - Ein tiefer Tauchgang

In componentWillReceiveProps aktualisieren Sie state, um mit props-Updates synchron zu bleiben.

Sobald state aktualisiert wurde, werden dann Felder in Abhängigkeit von statedo wiedergegeben!

6
SherylHohman

Diese Antwort ist eine Zusammenfassung von Brian Vaughns Artikel mit dem Titel Sie brauchen wahrscheinlich keinen abgeleiteten Zustand (7. Juni 2018).

Das Ableiten des Zustands von Requisiten ist ein Anti-Muster in all seinen Formen. Einschließlich der Verwendung des älteren componentWillReceiveProps und des neueren getDerivedStateFromProps.

Ziehen Sie die folgenden Lösungen in Betracht, anstatt den Status von Requisiten abzuleiten.

Zwei Best-Practice-Empfehlungen

function EmailInput(props) {
  return <input onChange={props.onChange} value={props.email} />;
}
// parent class
class EmailInput extends Component {
  state = { email: this.props.defaultEmail };

  handleChange = event => {
    this.setState({ email: event.target.value });
  };

  render() {
    return <input onChange={this.handleChange} value={this.state.email} />;
  }
}

// child instance
<EmailInput
  defaultEmail={this.props.user.email}
  key={this.props.user.id}
/>

Zwei Alternativen, wenn die Empfehlungen aus irgendeinem Grund für Ihre Situation nicht geeignet sind.

class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail,
    prevPropsUserID: this.props.userID
  };

  static getDerivedStateFromProps(props, state) {
    // Any time the current user changes,
    // Reset any parts of state that are tied to that user.
    // In this simple example, that's just the email.
    if (props.userID !== state.prevPropsUserID) {
      return {
        prevPropsUserID: props.userID,
        email: props.defaultEmail
      };
    }
    return null;
  }

  // ...
}
class EmailInput extends Component {
  state = {
    email: this.props.defaultEmail
  };

  resetEmailForNewUser(newEmail) {
    this.setState({ email: newEmail });
  }

  // ...
}
0
Mowzer

wie ich weiß, ist das, was redux tut, beim Ändern des Speicherzustands der Aufruf von componentWillRecieveProps, wenn Ihre Komponente in einen mutierten Zustand übergeht und Sie Ihre Komponente dann zwingen sollten,

1-Speicher-Zustandsänderung-2-Aufruf (ComponentWillRecieveProps (() => {3-Komponenten-Zustandsänderung}))

0