Redux:如何让两个减速机以特定的顺序响应相同的操作?

Redux:如何让两个减速机以特定的顺序响应相同的操作?,redux,Redux,我对Redux比较陌生,我有以下情况: 我的应用程序发出AJAX请求,从服务器获取第一个“message”对象 响应返回并发送{type:'RECEIVE_FIRST_MESSAGE',MESSAGE} 我的MessageReducer通过以下方式处理RECEIVE\u FIRST\u MESSAGE: A) 将action.message添加到state.messages B) 进行另一个AJAX调用以获取下一条消息(如果action.message.hasNextMessage) MySes

我对Redux比较陌生,我有以下情况:

  • 我的应用程序发出AJAX请求,从服务器获取第一个“message”对象
  • 响应返回并发送
    {type:'RECEIVE_FIRST_MESSAGE',MESSAGE}
  • 我的
    MessageReducer
    通过以下方式处理
    RECEIVE\u FIRST\u MESSAGE

    A) 将
    action.message
    添加到
    state.messages

    B) 进行另一个AJAX调用以获取下一条消息(如果
    action.message.hasNextMessage

  • My
    SessionReducer
    还通过将
    action.MESSAGE.sessionId
    添加到
    state.session.id
    来处理
    RECEIVE\u FIRST\u MESSAGE

  • 只有一个问题:当我获取第二条消息时,我需要使用从第一条消息获得的
    sessionId
    。但是由于
    MessageReducer
    SessionReducer
    之前运行,会话ID在
    MessageReducer
    尝试发出第二个AJAX请求时不处于状态

    我可以通过使用超时来“解决”这个问题,以确保
    MessageReducer
    在1毫秒后才发出第二个请求,但这感觉像是一种黑客/反模式

    TLDR

    当我有:

    • 具有
      状态两部分数据的动作(由两个不同的减速器处理)
    • 我想触发一个AJAX调用作为响应,它来自一个reducer
    • 我想添加一些状态(
      state.session.id
      )作为响应,来自reducer B

    如何确保reducer B在reducer A调用AJAX之前添加状态(以一种不会让Dan Abramov哭的方式)?

    第一件事。决不要从减速器内部进行AJAX调用。永远

    Reducer函数应该是纯粹的,没有任何副作用(比如HTTP请求)。相反,使用thunks对你有利。下面是一个示例,说明了您可能如何做到这一点

    从服务器返回第一条消息响应后,您将调度
    RECEIVE\u first\u message
    操作。这将同步更新原子状态。完成后,您可以检查消息是否有下一条消息。如果是,则调度一个新的异步操作以获取下一条消息。在该异步操作创建者中,您可以从状态原子获取会话ID,该会话ID保证会更新以响应您先前调度的
    RECEIVE\u FIRST\u消息
    操作

    如果你有任何问题,请告诉我

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

    第一件事。决不要从减速器内部进行AJAX调用。永远

    Reducer函数应该是纯粹的,没有任何副作用(比如HTTP请求)。相反,使用thunks对你有利。下面是一个示例,说明了您可能如何做到这一点

    从服务器返回第一条消息响应后,您将调度
    RECEIVE\u first\u message
    操作。这将同步更新原子状态。完成后,您可以检查消息是否有下一条消息。如果是,则调度一个新的异步操作以获取下一条消息。在该异步操作创建者中,您可以从状态原子获取会话ID,该会话ID保证会更新以响应您先前调度的
    RECEIVE\u FIRST\u消息
    操作

    如果你有任何问题,请告诉我

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

    你用的是像redux thunks或sagas这样的东西吗?如果它已经在您正在处理的消息中,为什么需要从会话中获取它?但是:你在减速器中调用Ajax?是的,我在使用thunks。至于为什么我会从
    状态获取ID
    。。。我想现在我想起来了,我不知道。我只是在想“一个操作会将ID添加到状态,一个单独的操作会将ID从状态中拉出来”,但是由于(正如您所指出的)我已经在操作中拥有了我所需要的一切,所以通过
    状态
    传递ID是完全没有必要的(好吧,除了以后的请求,但是这些请求没有时间问题)。谢谢如果你想让某样东西达到“根据定义,在这种情况下,你已经拥有了你所需要的一切”的效果,我很乐意接受。你使用的是redux thunks或sagas之类的东西吗?如果它已经在您正在处理的消息中,为什么需要从会话中获取它?但是:你在减速器中调用Ajax?是的,我在使用thunks。至于为什么我会从
    状态获取ID
    。。。我想现在我想起来了,我不知道。我只是在想“一个操作会将ID添加到状态,一个单独的操作会将ID从状态中拉出来”,但是由于(正如您所指出的)我已经在操作中拥有了我所需要的一切,所以通过
    状态
    传递ID是完全没有必要的(好吧,除了以后的请求,但是这些请求没有时间问题)。谢谢如果你想让某些东西达到“根据定义,在这种情况下,你已经拥有了你所需要的一切”的效果,我会很乐意接受它。这是有道理的:当我有一分钟的时间时,我会尝试从减速器中重构委托调用,并遵循你的模式。谢谢。这很有意义:当我有时间的时候,我会尝试从reducer中重构委托调用,并遵循您的模式。谢谢