Я все еще относительно новичок в 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])
);
Вы используете Promise.all() в вашем методе fetchData(): ваши действия отправляются параллельно, а не один за другим.
Чтобы убедиться, что вы вызываете первый объект назначения, а затем свойства, вы должны создать один конкретный создатель действия async для вашего компонента поиска. Этот создатель асинхронного действия будет реализовывать последующие запросы, которые вам нужны в этом случае.
Я согласен с @pierrepinard_2.
Используя promise.map от bluebird, вы сможете синхронно вызывать все заданные обещания.
Это сообщение при переполнении стека должно помочь вам в этом.
Сообщите нам, если он работает
connectDataFetchers