React / Redux state is empty in the second action call

I'm still relatively new to React / Redux, so I apologize if this is a simple question, but I haven't found a solution yet.

I have two actions:

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

they are combined with their relative gearboxes:

 // 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; } } 

and they are called from within the component (connectDataFetchers iterates through the called actions and returns them to the component for server-side rendering):

 // PROPTYPES // ============================================== Search.propTypes = { destination: PropTypes.object.isRequired, properties: PropTypes.array.isRequired }; // ACTIONS // ============================================== function mapStateToProps ({destination, properties}) { return {destination, properties}; } // CONNECT & EXPORT // ============================================== export default connect(mapStateToProps)( connectDataFetchers(Search, [loadDestination, loadProperties]) ); 

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

I need to run the first action (loadDestination), which will return an identifier, then I need to pass it to the second action in order to load properties with this location identifier.

If I hardcode the location identifier, this works fine, but if I try to access the state in loadProperties via getState() , it will return { destination: [], properties: [] } .

Is there a way to access the value from the first action through state?

DECISION

Managed to get this to work after a sentence from @ pierrepinard_2

I created a new action that dispatches two other actions in the order I needed:

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

then in the component I just request one action:

 export default connect(mapStateToProps)( connectDataFetchers(Search, [loadSearch]) ); 
+5
source share
2 answers

You use Promise.all () in your fetchData () method: your actions are sent in parallel, and not one after another.

To ensure that you call the first target and then the properties, you must create one specific creator of the async action for your search component. This asynchronous action creator will implement the subsequent requests that you need in this case.

+3
source

I agree with @ pierrepinard_2.

Using the promise.map from bluebird, you can synchronously invoke all the given promises.

This stack overflow message should help you with this.

Let us know if it works.

0
source

Source: https://habr.com/ru/post/1247587/


All Articles