React / Redux State пуст во втором вызове действия

5

Я все еще относительно новичок в React/Redux, поэтому извиняюсь, если это простой вопрос, но я еще не нашел решение.

У меня есть два действия:

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

они сочетаются с их относительными редукторами:

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

и они вызываются изнутри компонента (connectDataFetchers перебирает вызываемые действия и возвращает их компоненту для рендеринга на стороне сервера):

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

Мне нужно запустить первое действие (loadDestination), которое вернет идентификатор, затем необходимо передать второму действию, чтобы загрузить свойства с этим идентификатором местоположения.

Если я жестко задаю идентификатор location, это работает нормально, но если я попытаюсь получить доступ к состоянию в loadProperties через getState(), то он вернет { destination: [], properties: [] }.

Есть ли способ получить доступ к значению из первого действия через состояние?

РЕШЕНИЕ

Удалось заставить это работать после предложения от @pierrepinard_2

Я создал новое действие, которое отправляет два других действия в том порядке, в котором я нуждался:

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

то в компоненте я просто запрашиваю одно действие:

export default connect(mapStateToProps)(
    connectDataFetchers(Search, [loadSearch])
);
  • 0
    Не могли бы вы рассказать, как <Search> вызывает loadDestination & loadProperties?
  • 0
    @DamienLeroux - я добавил еще немного кода из компонента поиска и функцию connectDataFetchers
Теги:
react-redux
redux

2 ответа

3
Лучший ответ

Вы используете Promise.all() в вашем методе fetchData(): ваши действия отправляются параллельно, а не один за другим.

Чтобы убедиться, что вы вызываете первый объект назначения, а затем свойства, вы должны создать один конкретный создатель действия async для вашего компонента поиска. Этот создатель асинхронного действия будет реализовывать последующие запросы, которые вам нужны в этом случае.

  • 0
    Я попробовал это, первоначально вызывая две функции в отдельной функции, но это не прикреплялось к соответствующим переменным в mapStateToProps. Как мне сохранить эти отношения?
  • 0
    Я не понимаю, что вы имеете в виду. Функция mapStateToProps () извлекает ваши реквизиты из единственного состояния вашего приложения. Это проблема с порядком получения запросов API? Если вы используете промежуточное программное обеспечение redux-thunk для обработки асинхронных запросов и хотите связать вызовы dispatch () с помощью then (), обязательно всегда возвращайте обещания создателям асинхронных действий (дополнительную информацию см. На github.com/gaearon/redux-thunk # композиция ). Например, вы должны «вернуть отправку (...);» в твоих действиях создатели.
Показать ещё 1 комментарий
0

Я согласен с @pierrepinard_2.

Используя promise.map от bluebird, вы сможете синхронно вызывать все заданные обещания.

Это сообщение при переполнении стека должно помочь вам в этом.

Сообщите нам, если он работает

Ещё вопросы

Сообщество Overcoder
Наверх
Меню