Come attivare la richiamata dopo l'aggiornamento dello stato in Redux?


86

In React, lo stato non viene aggiornato istantaneamente, quindi possiamo usare la richiamata in setState(state, callback) . Ma come farlo in Redux?

Dopo aver chiamato il this.props.dispatch(updateState(key, value)) , devo fare qualcosa con lo stato aggiornato immediatamente.

C'è un modo in cui posso chiamare una richiamata con lo stato più recente come quello che faccio in React?


Usi thunk?
Pranesh Ravi

1
Penso dispatch()sia un'attività sincrona. Lo stato aggiornato dovrebbe essere disponibile nella riga successiva.
Pranesh Ravi

4
@PraneshRavi Lo pensavo. Ma ho il vecchio stato. Non ho usato thunk.
Brick Yang,


1
Sì, l'invio è sincrono, ma il successivo aggiornamento degli oggetti di scena del componente non lo è. Pertanto lo stato di redux viene aggiornato nella riga successiva, ma gli oggetti di scena del componente non lo sono ancora.
amik

Risposte:


113

componente dovrebbe essere aggiornato per ricevere nuovi oggetti di scena.

ci sono modi per raggiungere il tuo obiettivo:

1. componentDidUpdate controlla se il valore è cambiato, quindi fai qualcosa ..

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

2. redux-promise (il middleware invierà il valore risolto della promessa)

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

quindi in componente

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

quindi in componente

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

6
Nel tuo redux-thunkesempio, usi dispatchcome se fosse sincrono. È così?
Danny Harding

2
@DannyHarding dispatchnon è sincrono. Senza il Promise.resolve(), this.props.valuerestituirebbe ancora il vecchio valore. È ancora necessario un certo tipo di differimento asincrono ( setTimeoutad esempio, funzionerebbe anche il riferimento dall'interno di a ).
Drazen Bjelovuk

4
@DrazenBjelovuk Mi chiedo perché la funzione updateState nell'esempio redux-thunk ha dispatch (someAction) immediatamente seguito da return Promise.resolve (). La promessa si risolve immediatamente, il che immagino creerebbe una race condition tra l'aggiornamento del redux store e il .then chiamato nel componente. Poiché l'invio non restituisce una promessa né accetta una richiamata, non credo che questo sia un modo accurato per sapere quando il redux store è stato aggiornato. Penso che la risposta di Just-Boris sia corretta in questo caso
Danny Harding

2
@DannyHarding Sì, sarei d'accordo sul fatto che questo metodo probabilmente non è una garanzia sicura del fuoco, illustrando solo che l'invio non è sincrono.
Drazen Bjelovuk

1
Sto cercando di utilizzare la soluzione redux-thunk qui, ma ottengo solo TypeError: _this.props.dispatch is not a function?
Krillko

14

Il punto più importante di React è il flusso di dati unidirezionale. Nel tuo esempio ciò significa che l'invio di un'azione e la gestione del cambiamento di stato devono essere disaccoppiati.

Non dovresti pensare come "l'ho fatto A, ora Xdiventa Ye lo gestisco", ma "cosa faccio quando Xdiventa Y", senza alcuna relazione con A. Lo stato del negozio può essere aggiornato da più fonti, oltre al tuo componente, anche Time Travel può cambiare stato e non sarà passato attraverso il tuo Apunto di spedizione.

Fondamentalmente questo significa che dovresti usare componentWillReceivePropscome è stato proposto da @Utro


Questa è la risposta che sta davvero cercando (anche se sembra che non ne sia a conoscenza ..)
refaelio

1
Sono d'accordo ma questo sembra essere considerato un antipattern: hackernoon.com/…
Giacomo Cerquone

1
cosa facciamo ora che componentWillReceivePropsè deprecato? static getDerivedStateFromProps()non sembra un sostituto adatto in quanto non può richiamare una richiamata, per quanto ne so
M3RS

9

Con API Hooks:

useEffect con il puntello come input.

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

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

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

   }, [value])

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

La risposta accettata è stata scritta prima di React Hooks. Questa dovrebbe essere la risposta accettata ora dopo l'introduzione degli hook. È un modo più reattivo per gestire i cambiamenti.
tif

5

È possibile utilizzare subscribelistener e verrà chiamato quando viene inviata un'azione. All'interno dell'ascoltatore otterrai gli ultimi dati del negozio.

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


2
subscribesi attiva solo quando viene eseguita un'azione. Non c'è modo di subscribefarti sapere se la tua chiamata API ha restituito dei dati .. penso! : D
Mihir

Potresti inviare un'altra azione quando la tua richiesta viene completata (con successo o senza successo).
Jam

Non sono convinto che nessuna delle altre soluzioni proposte qui funzioni effettivamente, perché non vedo un modo per risolvere una promessa o una richiamata dopo l'aggiornamento dello stato. Questo metodo viene chiamato per ogni aggiornamento del negozio, non solo per quello che avviene dopo il tuo evento, ma non dovrebbe essere troppo difficile da aggirare. In particolare, il collegamento scrive un'utilità di ObservStore personalizzata dalla pagina a cui si è collegati è molto utile.
Nat Kuhn,

Pagina di collegamento non trovata
Bharat Modi

2

È possibile utilizzare un thunk con una richiamata

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

Perfetto per quello che mi serviva!
JSON C11

-1

Come soluzione semplice puoi usare: redux-promise

Ma se usi redux-thunk , dovresti fare qc in questo modo:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.