2016-04-21 16 views
5

Nadal jestem względnie nowy w React/Redux, więc przepraszam, jeśli jest to proste pytanie, ale jeszcze nie znalazłem rozwiązania.React/Redux State jest pusty podczas drugiego połączenia akcji

mam dwa działania:

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

te są połączone z ich odpowiednich reduktorów:

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

i zostały wywołane w składniku (connectDataFetchers przechodzi poprzez zwanych działaniach i zwraca do komponentu do renderowania po stronie serwera):

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

trzeba uruchomić pierwsze działanie (loadDestination), który powróci identyfikator musi następnie przechodzą następnie do drugiego działania załadować własności w tym miejscu identyfikatora.

Jeśli twarde kodowanie locationID to działa dobrze, ale jeśli próbuję uzyskać dostęp do stanu w loadProperties przez getState(), to zwraca { destination: [], properties: [] }.

Czy istnieje sposób na uzyskanie dostępu do wartości z pierwszej akcji za pośrednictwem stanu?

ROZWIĄZANIE

Udało nam się uzyskać to do pracy zgodnie z sugestią @ pierrepinard_2

stworzyłem nową akcję, która wywołuje dwa inne działania w celu potrzebowałem:

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

następnie w komponencie proszę o jedno działanie:

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

+0

mógłbyś podzielić się jak wzywa loadDestination & loadProperties? –

+0

@DamienLeroux - Dodałem trochę więcej kodu ze składnika wyszukiwania oraz funkcję 'connectDataFetchers' – Paul

Odpowiedz

3

użyć Promise.all() w metodzie swojej fetchData(): twoje działania są wysyłane równolegle, a nie jeden po drugim.

Aby upewnić się, że wywołasz pierwsze miejsce docelowe, a następnie właściwości, powinieneś utworzyć określonego kreatora akcji asynchronicznych dla składnika Wyszukiwanie. Ten twórca akcji asynchronicznych implementowałby kolejne żądania, których potrzebujesz w tym przypadku.

+0

Próbowałem tego, początkowo wywołując dwie funkcje w ramach oddzielnej funkcji, ale która nie dołączała do odpowiednich zmiennych w mapStateToProps. Jak utrzymać ten związek? – Paul

+0

Nie rozumiem, co masz na myśli. Funkcja mapStateToProps() pobiera rekwizyty z jednego i jedynego stanu aplikacji. Czy jest to problem z kolejnością otrzymywania żądań API? Jeśli używasz oprogramowania pośredniczącego redux-thunk do obsługi żądań asynchronicznych i chcesz połączyć wywołania dispatch() z tym(), pamiętaj, aby zawsze zwracać obietnice w swoich twórcach akcji asynchronicznych (więcej informacji na https://github.com/gaearon/redux-thunk # composition). Na przykład powinieneś "zwrócić wysyłkę (...);" w twoich twórcach akcji. –

+0

Dzięki @ pierrepinard_2 - po sugestii redux-thunk mam to do pracy i dodałem rozwiązanie powyżej – Paul

0

Zgadzam się z @ pierrepinard_2.

Korzystając z bluebird, powinieneś móc zsynchronizować wszystkie dane obietnice.

Ta post on stack overflow powinna ci w tym pomóc.

Daj nam znać, jeśli działa

Powiązane problemy