Wie kann ein Rückruf nach dem Aktualisieren des Status in Redux ausgelöst werden?


85

In React wird der Status nicht sofort aktualisiert, sodass wir den Rückruf in verwenden können setState(state, callback). Aber wie geht das in Redux?

Nach dem Aufruf von this.props.dispatch(updateState(key, value))muss ich sofort etwas mit dem aktualisierten Status tun.

Gibt es eine Möglichkeit, einen Rückruf mit dem neuesten Status wie in React aufzurufen?


Haben Sie verwenden thunk?
Pranesh Ravi

1
Ich denke, es dispatch()ist eine synchrone Aktivität. Der aktualisierte Status sollte in der nächsten Zeile verfügbar sein.
Pranesh Ravi

3
@PraneshRavi Ich dachte schon. Aber ich habe den alten Staat. Ich habe nicht benutzt thunk.
Brick Yang


1
Ja, der Versand ist synchron, die spätere Aktualisierung der Requisiten der Komponente jedoch nicht. Daher wird der Redux-Status in der nächsten Zeile aktualisiert, die Requisiten der Komponente jedoch noch nicht.
Amik

Antworten:


111

Komponente sollte aktualisiert werden, um neue Requisiten zu erhalten.

Es gibt Möglichkeiten, Ihr Ziel zu erreichen:

1. componentDidUpdate Überprüfen Sie, ob der Wert geändert wurde, und tun Sie dann etwas.

 componentDidUpdate(prevProps){
     if(prevProps.value !== this.props.value){ alert(prevProps.value) }
  }

2. Redux-Versprechen (Middleware versendet den aufgelösten Wert des Versprechens)

export const updateState = (key, value)=>
Promise.resolve({
  type:'UPDATE_STATE',
  key, value
})

dann in Komponente

this.props.dispatch(updateState(key, value)).then(()=>{
   alert(this.props.value)
})

2. Redux-Thunk

export const updateState = (key, value) => dispatch => {
  dispatch({
    type: 'UPDATE_STATE',
    key,
    value,
  });
  return Promise.resolve();
};

dann in Komponente

this.props.dispatch(updateState(key, value)).then(()=>{
   alert(this.props.value)
})

6
In Ihrem redux-thunkBeispiel verwenden Sie es so, dispatchals ob es synchron wäre. Ist das der Fall?
Danny Harding

2
@DannyHarding dispatchist nicht synchron. Ohne die Promise.resolve(), this.props.valuewürde immer noch den alten Wert zurück. Es ist immer noch eine Art asynchroner Aufschub erforderlich (das Referenzieren aus einem heraus setTimeoutwürde beispielsweise auch funktionieren).
Drazen Bjelovuk

4
@DrazenBjelovuk Ich frage mich, weil die updateState-Funktion im Redux-Thunk-Beispiel den Versand (someAction) hat, unmittelbar gefolgt von der Rückgabe von Promise.resolve (). Das Versprechen wird sofort aufgelöst, was meiner Meinung nach eine Race-Bedingung zwischen dem Redux-Store-Update und dem in der Komponente aufgerufenen .then schaffen würde. Da der Versand kein Versprechen zurückgibt oder keinen Rückruf annimmt, ist dies meiner Meinung nach keine genaue Methode, um festzustellen, wann der Redux-Speicher aktualisiert wurde. Ich denke, dass die Antwort von just-boris in diesem Fall richtig ist
Danny Harding

2
@DannyHarding Ja, ich würde zustimmen, dass diese Methode wahrscheinlich keine sichere Brandgarantie ist, nur um zu veranschaulichen, dass der Versand nicht synchron ist.
Drazen Bjelovuk

1
Ich versuche hier die Redux-Thunk-Lösung zu verwenden, aber ich bekomme nur TypeError: _this.props.dispatch is not a function?
Krillko

13

Der wichtigste Punkt bei React ist der Datenfluss in eine Richtung. In Ihrem Beispiel bedeutet dies, dass das Versenden einer Aktion und die Behandlung von Statusänderungen entkoppelt werden sollten.

Sie sollten nicht denken wie "Ich habe es getan A, jetzt Xwird es Yund ich kümmere mich darum ", sondern "Was mache ich, wenn es Xwird Y", ohne irgendeine Beziehung zu A. Der Speicherstatus kann aus mehreren Quellen aktualisiert werden. Zusätzlich zu Ihrer Komponente kann Time Travel auch den Status ändern und wird nicht über Ihren Status weitergeleitetA Versandpunkt weitergeleitet.

Grundsätzlich bedeutet dies, dass Sie verwenden sollten, componentWillReceivePropswie es von @Utro vorgeschlagen wurde


Dies ist die Antwort, nach der op wirklich sucht (obwohl es so aussieht, als ob er sich dessen nicht bewusst ist ..)
refaelio

1
Ich stimme zu, aber dies scheint als Antimuster
Giacomo Cerquone

1
Was machen wir jetzt, wenn componentWillReceivePropses veraltet ist? static getDerivedStateFromProps()scheint kein geeigneter Ersatz zu sein, da es, soweit ich das
beurteilen

6

Mit Hooks API:

useEffect mit der Requisite als Eingabe.

import React, { useEffect} from 'react'
import { useSelector } from 'react-redux'

export default function ValueComponent() {
   const value = useSelectror(store => store.pathTo.value)

   useEffect(() => {
     console.log('New value', value) 
     return () => {
        console.log('Prev value', value) 
     }

   }, [value])

   return <div> {value} </div>
}

Die akzeptierte Antwort wurde vor React Hooks geschrieben. Dies sollte jetzt nach der Einführung von Hooks die akzeptierte Antwort sein. Es ist eine reaktivere Art, mit Änderungen umzugehen.
Bis zum

5

Du könntest benutzen subscribe Listener verwenden und er wird aufgerufen, wenn eine Aktion ausgelöst wird. Im Listener erhalten Sie die neuesten Geschäftsdaten.

http://redux.js.org/docs/api/Store.html#subscribelistener


2
subscribeWird nur ausgelöst, wenn eine Aktion ausgelöst wird. Es gibt keine Möglichkeit subscribe, Sie wissen zu lassen, ob Ihr API-Aufruf Daten zurückgegeben hat. Ich denke! : D
Mihir

Sie können eine andere Aktion auslösen, wenn Ihre Anforderung abgeschlossen ist (erfolgreich oder erfolglos).
Jam

Ich bin nicht davon überzeugt, dass eine der anderen hier vorgeschlagenen Lösungen tatsächlich funktioniert, da ich keinen Weg sehe, ein Versprechen zu lösen oder einen Rückruf zu starten, nachdem der Status aktualisiert wurde. Diese Methode wird für jedes Store-Update aufgerufen, nicht nur für das nach Ihrem Ereignis, sondern es sollte auch nicht zu schwierig sein, dies zu umgehen. Insbesondere der Link zum Schreiben eines benutzerdefinierten ObservStore-Dienstprogramms von der Seite, auf die Sie verlinkt haben, ist sehr hilfreich.
Nat Kuhn

Link-Seite nicht gefunden
Bharat Modi

2

Sie können einen Thunk mit einem Rückruf verwenden

myThunk = cb => dispatch =>
  myAsyncOp(...)
    .then(res => dispatch(res))
    .then(() => cb()) // Do whatever you want here.
    .catch(err => handleError(err))

Perfekt für das, was ich brauchte!
JSON C11

-1

Als einfache Lösung können Sie verwenden: Redux-Versprechen

Aber wenn Sie Redux-Thunk verwenden , sollten Sie Folgendes tun:

function addCost(data) {
  return dispatch => {
    var promise1 = new Promise(function(resolve, reject) {
      dispatch(something);
     });
    return promise1;
  }
}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.