2016-04-21 15 views
5

Ich bin noch relativ neu zu React/Redux so Entschuldigung, wenn das eine einfache Frage ist, aber ich habe noch eine Lösung zu finden.React/Redux State ist leer beim zweiten Aktionsaufruf

Ich habe eine zwei Aktionen:

// DESTINATIONS 
// ============================================== 

export const DESTINATION_REQUEST = 'DESTINATION_REQUEST'; 
export const DESTINATION_SUCCESS = 'DESTINATION_SUCCESS'; 
export const DESTINATION_FAILURE = 'DESTINATION_FAILURE'; 

export function loadDestination (params, query) { 

    const state = params.state ? `/${params.state}` : ''; 
    const region = params.region ? `/${params.region}` : ''; 
    const area = params.area ? `/${params.area}` : ''; 

    return (dispatch) => { 
     return api('location', {url: `/accommodation${state}${region}${area}`}).then((response) => { 
      const destination = formatDestinationData(response); 

      dispatch({ 
       type: DESTINATION_SUCCESS, 
       destination 
      }); 
     }); 
    }; 
} 





// PROPERTIES 
// ============================================== 

export const PROPERTIES_REQUEST = 'PROPERTIES_REQUEST'; 
export const PROPERTIES_SUCCESS = 'PROPERTIES_SUCCESS'; 
export const PROPERTIES_FAILURE = 'PROPERTIES_FAILURE'; 

export function loadProperties (params, query, rows = 24) { 

    return (dispatch, getState) => { 

     console.log(getState()); 

     return api('search', {locationId: xxxxxx, rows: rows}).then((response) => { 
      const properties = response.results.map(formatPropertiesData); 

      dispatch({ 
       type: PROPERTIES_SUCCESS, 
       properties 
      }); 
     }); 
    }; 
} 

diese mit ihrer relativen Reduzierungen kombiniert werden:

// DESTINATIONS REDUCERS 
// ============================================== 

export default function destination (state = [], action) { 
    switch (action.type) { 
    case DESTINATION_SUCCESS: 
     return action.destination; 
    default: 
     return state; 
    } 
} 





// PROPERTIES REDUCERS 
// ============================================== 

export default function properties (state = [], action) { 
    switch (action.type) { 
    case PROPERTIES_SUCCESS: 
     return action.properties; 
    default: 
     return state; 
    } 
} 

und sie sind aus einer Komponente aufgerufen (connectDataFetchers Schleifen durch die genannten Aktionen und gibt sie zur Komponente für serverseitiges Rendering):

export default function connectDataFetchers (Component, actionCreators) { 
 
    return class DataFetchersWrapper extends React.Component { 
 
     static propTypes = { 
 
      dispatch: React.PropTypes.func.isRequired, 
 
      location: React.PropTypes.object.isRequired, 
 
      params: React.PropTypes.object.isRequired 
 
     }; 
 
     
 
     static fetchData (dispatch, params = {}, query = {}) { 
 
      return Promise.all(
 
       actionCreators.map((actionCreator) => dispatch(actionCreator(params, query))) 
 
      ); 
 
     } 
 

 
     componentDidMount() { 
 
      DataFetchersWrapper.fetchData(
 
       this.props.dispatch, 
 
       this.props.params, 
 
       this.props.location.query 
 
      ); 
 
     } 
 

 
     render() { 
 
      return (
 
       <Component {...this.props} /> 
 
      ); 
 
     } 
 
    }; 
 
}

ich brauche die erste Aktion (loadDestination) laufen, die eine ID benötigt wird dann wieder auf, dann auf die zweite Aktion übergeben Eigenschaften mit dieser Stelle ID zu laden.

Wenn ich eine locationID fest codiere, funktioniert das gut, aber wenn ich versuche, auf den Zustand in loadProperties über getState() zuzugreifen, dann gibt es { destination: [], properties: [] } zurück.

Gibt es eine Möglichkeit, auf den Wert der ersten Aktion über den Status zuzugreifen?

SOLUTION

Managed dies von @ nach dem Vorschlag zur Arbeit kommen pierrepinard_2

ich eine neue Aktion erstellt, die die beiden anderen Aktionen in der Reihenfolge entsendet ich brauchte:

// SEARCH 
 
// ============================================== 
 

 
export function loadSearch (params, query) { 
 
    
 
    return (dispatch) => { 
 
     return dispatch(
 
      loadDestination(params, query) 
 
     ).then(() => { 
 
      return dispatch(
 
       loadProperties(params, query) 
 
      ) 
 
     }) 
 
    } 
 
} 
 

 
// DESTINATIONS 
 
// ============================================== 
 

 
export const DESTINATION_REQUEST = 'DESTINATION_REQUEST'; 
 
export const DESTINATION_SUCCESS = 'DESTINATION_SUCCESS'; 
 
export const DESTINATION_FAILURE = 'DESTINATION_FAILURE'; 
 

 
export function loadDestination (params, query) { 
 

 
    const state = params.state ? `/${params.state}` : ''; 
 
    const region = params.region ? `/${params.region}` : ''; 
 
    const area = params.area ? `/${params.area}` : ''; 
 

 
    return (dispatch) => { 
 
     return api('location', {url: `/accommodation${state}${region}${area}`}).then((response) => { 
 
      const destination = formatDestinationData(response); 
 
      
 
      dispatch({ 
 
       type: DESTINATION_SUCCESS, 
 
       destination 
 
      }); 
 
     }); 
 
    }; 
 
} 
 
    
 
    // PROPERTIES 
 
// ============================================== 
 

 
export const PROPERTIES_REQUEST = 'PROPERTIES_REQUEST'; 
 
export const PROPERTIES_SUCCESS = 'PROPERTIES_SUCCESS'; 
 
export const PROPERTIES_FAILURE = 'PROPERTIES_FAILURE'; 
 

 
export function loadProperties (params, query, rows = 24) { 
 

 
    return (dispatch, getState) => { 
 
     return api('search', {locationId: getState().destination.id, rows: rows}).then((response) => { 
 
      const properties = response.results.map(formatPropertiesData); 
 

 
      dispatch({ 
 
       type: PROPERTIES_SUCCESS, 
 
       properties 
 
      }); 
 
     }); 
 
    }; 
 
}

dann in der Komponente ich nur die eine Aktion anfordern:

export default connect(mapStateToProps)(
 
    connectDataFetchers(Search, [loadSearch]) 
 
);

+0

Können Sie teilen, wie nennt loadDestination & LoadProperties? –

+0

@DamenLeroux - Ich habe etwas mehr Code aus der Suchkomponente plus der 'connectDataFetchers' Funktion hinzugefügt – Paul

Antwort

3

Sie verwenden Promise.all() in der FetchData() -Methode: Ihre Aktionen werden parallel versendet, nicht eins nach dem anderen.

Um sicherzustellen, dass Sie das erste Ziel und dann die Eigenschaften aufrufen, sollten Sie einen bestimmten asynchronen Aktionsgenerator für Ihre Suchkomponente erstellen. Dieser Ersteller von asynchronen Aktionen würde die nachfolgenden Anforderungen implementieren, die Sie in diesem Fall benötigen.

+0

Ich habe versucht, die beiden Funktionen zunächst in einer separaten Funktion aufzurufen, die aber nicht an die entsprechenden Variablen im mapStateToProps angehängt wurden. Wie pflege ich diese Beziehung? – Paul

+0

Ich verstehe nicht, was du meinst. Die Funktion mapStateToProps() ruft Ihre Requisiten aus dem einzigen Status Ihrer App ab. Ist es ein Problem mit der Reihenfolge, in der die API-Anfragen eingehen? Wenn Sie redux-thunk-Middleware verwenden, um Ihre asynchronen Anfragen zu bearbeiten und dispatch() -Aufrufe mit then() zu ketten, stellen Sie sicher, dass Sie die Versprechen in Ihren asynchronen Aktions-Erstellern immer zurückgeben (weitere Informationen in https://github.com/gaearon)/redux-thunk # Zusammensetzung). Zum Beispiel sollten Sie "Versand zurück (...);" in deinen Aktionsmachern. –

+0

Danke @ pierrepinard_2 - dem Redux-Thunk-Vorschlag folgend habe ich das zum Laufen gebracht und die obige Lösung hinzugefügt – Paul

0

Ich stimme @ pierrepinard_2 zu.

Mit promise.map von Bluebird sollten Sie in der Lage sein, alle gegebenen Versprechen synchron zu nennen.

Diese post on stack overflow sollte Ihnen dabei helfen.

Lassen Sie uns wissen, ob es funktioniert

Verwandte Themen