Javascript - действия Redux не выполняются последовательно - PullRequest
0 голосов
/ 09 января 2019

У меня есть ситуация, когда мне нужно, чтобы 2 Redux Actions выполнялись последовательно. Контекст заключается в том, что пользователь нажимает кнопку «Просмотр», и я хочу отображать загрузчик до тех пор, пока головоломка не будет завершена.

function mapDispatchToProps(dispatch) {
  return {
    onPreview: () => {
      dispatch(generatePreview());
    },
  };
}

Для этого я использую промежуточное программное обеспечение redux-thunk , и первое действие, которое я хочу выполнить, возвращает Promise.resolve(), а мое второе действие - then():

export function generatingPreview() {
  return dispatch => {
    dispatch({
      type: GENERATING_PREVIEW,
    });
    return Promise.resolve();
  };
}

export function generatePreview() {
  return (dispatch, getState) => {
    dispatch(generatingPreview()).then(() => {
      const state = getState();
      const conf = state.getIn(['login', 'conf']).toJS();
      const wordList = state.getIn(['login', 'wordList']);
      try {
        const newPuzzle = Wordfind.newPuzzleLax(wordList, conf);
        dispatch(generatePreviewSuccess(newPuzzle));
      } catch (err) {
        dispatch(generatePreviewError(err.message));
      }
    });
  };
}

export function generatePreviewError(error) {
  return {
    type: GENERATE_PREVIEW_ERROR,
    error,
  };
}

export function generatePreviewSuccess(payload) {
  return {
    type: GENERATE_PREVIEW_SUCCESS,
    payload,
  };
}

К сожалению, загрузчик никогда не появляется. Я console.logged состояние, устанавливая загрузку в true, когда мой компонент рендерит, и он меняется! Я вижу журнал, но не загрузчик, компонент не выполняет рендеринг до тех пор, пока не будут отправлены действия generatePreviewSuccess() или generatePreviewError(). И это не проблема загрузчика, если я заменю функцию newPuzzleLax на цикл, чтобы выделить достаточно времени для его просмотра, я смогу это увидеть!

Моя теория заключается в том, что эта функция Wordfind.newPuzzleLax(wordList, conf), которую я использую для создания головоломки, блокирует очередь действий, потому что в Chrome Redux Tools я вижу первое действие, появляющееся одновременно со вторым: Ссылка на функцию .

enter image description here

Если я добавлю задержку в 1 микросекунду между отправкой двух действий, появится загрузчик ... но мне бы очень хотелось понять, что происходит. Заранее спасибо. Если это поможет, я использую реактивную модель

Я также попытался преобразовать функцию, генерирующую головоломку, в асинхронную, выполнив следующее:

const wordFindAsync = async (wordList, conf) =>
  Wordfind.newPuzzleLax(wordList, conf);

export function generatePreview() {
  return (dispatch, getState) => {
    dispatch(generatingPreview())
      .then(() => {
        const state = getState();
        const conf = state.getIn(['login', 'conf']).toJS();
        const wordList = state.getIn(['login', 'wordList']);
        wordFindAsync(wordList, conf);
      })
      .then(res => dispatch(generatePreviewSuccess(res)))
      .catch(err => {
        dispatch(generatePreviewError(err.message));
      });
  };
}

1 Ответ

0 голосов
/ 09 января 2019

Во второй версии вы не вернете обещание с wordFindAsync(wordList, conf) обратно в исходную цепочку обещаний, и к тому времени оно не будет решено / ожидание к следующему then.

export function generatePreview() {
  return (dispatch, getState) => {
    dispatch(generatingPreview())
      .then(() => {
        const state = getState();
        const conf = state.getIn(['login', 'conf']).toJS();
        const wordList = state.getIn(['login', 'wordList']);
        return wordFindAsync(wordList, conf); // ? return your promise here 
      })
      .then(res => dispatch(generatePreviewSuccess(res)))
      .catch(err => {
        dispatch(generatePreviewError(err.message));
      });
  };
}

Вот простой пример, демонстрирующий поведение, на которое я ссылаюсь.

Этот будет ждать только 1 секунду, пока регистрация не будет завершена:

const waitOneSec = () =>
  new Promise(resolve => {
    console.log("waiting 1 secoond");
    setTimeout(resolve, 1000);
  });

waitOneSec()
  .then(() => {
    waitOneSec(); // Promise not returned
  })
  .then(() => console.log("done"));

Принимая во внимание, что этот будет ждать целых 2 секунды, пока регистрация не будет завершена:

const waitOneSec = () =>
  new Promise(resolve => {
    console.log("waiting 1 secoond");
    setTimeout(resolve, 1000);
  });

waitOneSec()
  .then(() => {
    return waitOneSec(); // ? Promise returned
  })
  .then(() => console.log("done"));

Надеюсь, это поможет.

...