我对Redux比较新,我有以下情况:
{type: 'RECEIVE_FIRST_MESSAGE', message}
我的MessageReducer
处理RECEIVE_FIRST_MESSAGE
:
A)将action.message
添加到state.messages
B)进行另一次AJAX调用以获取下一条消息(如果action.message.hasNextMessage
)
我的SessionReducer
也处理RECEIVE_FIRST_MESSAGE
,将action.message.sessionId
添加到state.session.id
只有一个问题:当我获取第二条消息时,我需要使用我从第一条消息中获得的sessionId
。但由于MessageReducer
在SessionReducer
之前运行,因此会话ID不在MessageReducer
尝试发出第二个AJAX请求时的状态。
我可以解决"这可以通过使用超时来确保MessageReducer
在1毫秒之后不会发出第二个请求,但这感觉就像是黑客/反模式。
TLDR
当我有:
state
两部分数据的动作(由两个不同的减速器处理)state.session.id
)作为响应
如何确保减速器B在减速器A进行AJAX调用之前添加状态(以不会让Dan Abramov哭泣的方式)?
答案 0 :(得分:5)
首先要做的事情。切勿从减速机内部进行AJAX调用。永远。 https://www.youtube.com/watch?v=Q-lv8kyYrqQ
Reducer函数应该是纯粹的,没有任何副作用(如HTTP请求)。相反,使用thunks对你有利。以下是如何执行此操作的示例。
从服务器收到第一条消息响应后,您将调度RECEIVE_FIRST_MESSAGE
操作。这将同步更新state atom。完成后,您可以检查消息是否有下一条消息。如果是,则调度新的异步操作以获取下一条消息。在异步操作创建器中,您可以从state atom获取会话ID,该会话ID保证在响应您之前发送的RECEIVE_FIRST_MESSAGE
操作时进行更新。
如果您有任何问题,请与我们联系。
// getFirstMessageFromServer() and getNextMessageFromServer() are thunks and async action creators
// fetchFirstMessage() and fetchNextMessage() make HTTP requests
function getFirstMessageFromServer() {
return (dispatch, getState) => {
return fetchFirstMessage()
.then(message => {
dispatch({ type: 'RECEIVE_FIRST_MESSAGE', message });
if (message.hasNextMessage) dispatch(getNextMessageFromServer());
return message;
});
};
}
function getNextMessageFromServer() {
return (dispatch, getState) => {
const { id: sessionId } = getState().session.id;
return fetchNextMessage(sessionId)
.then(nextMessage => {
dispatch({ type: 'RECEIVE_NEXT_MESSAGE', message: nextMessage });
return nextMessage;
});
};
}
const rootReducer = combineReducers({
session: sessionReducer,
messages: messagesReducer
});
const initialMessages = [];
function messagesReducer(state = initialMessages, action) {
switch(action.type) {
case 'RECEIVE_FIRST_MESSAGE':
return state.concat(action.message);
case 'RECEIVE_NEXT_MESSAGE':
return state.concat(action.message);
default:
return state;
}
}
const initialSession = { id: null };
function sessionReducer(state = initialSession, action) {
switch(action.type) {
case 'RECEIVE_FIRST_MESSAGE':
return {
...state,
id: action.message.sessionId
};
default:
return state;
}
}