it-roy-ru.com

ReactJS + Redux: Как дождаться завершения отправки, прежде чем переходить к следующему шагу?

В проекте ReactJS + Redux у меня есть метод, в котором он делает запрос API. В случае успеха я хотел бы отправить другого создателя действия и дождаться его завершения. Затем, когда он завершится, перейдите к следующему шагу.

В настоящее время следующий код выполняет диспетчеризацию, где он выполняет еще один вызов API, но даже до того, как состояние обновляется посредством диспетчеризации, он немедленно выполняет window.location.href ='http://localhost:3005/#/Home', а затем диспетчеризация завершается.

Итак, как я могу дождаться завершения функции dispatch(actions.updateUserInfo(userInfo.username)), прежде чем выполнять следующую строку кода, window.location.href ='http://localhost:3005/#/Home'?

Вот создатель действия:

  loggingIn(userInfo) {

    var userInfoBody = {
        'username': `${userInfo.username}`,
        'password': `${userInfo.password}`
    }

    var configuration = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(userInfoBody)
    }

    return function(dispatch) {
      fetch('https://backendserver.com:8080/creds', configuration)
      .then(response => response.json())
      .then(response => {
        //Would like to finish this dispatch completely before start executing window.location.href ='http://localhost:3005/#/Home'
        dispatch(actions.updateUserInfo(userInfo.username))
        window.location.href ='http://localhost:3005/#/Home'
      })
      .catch((error) => {
        console.log("Error: ", error)
      })
    }

Заранее спасибо

5
user3259472

Вероятно, самый редукционный способ сделать это - ввести еще одно действие, на которое вы будете реагировать, выполняя свои вещи window.location.href = '...'.

Поскольку избыточность можно считать «однопоточной», вы можете быть уверены, что между каждым вызовом для отправки ваше дерево состояний полностью обновляется.

dispatch(actions.updateUserInfo(userInfo.username))
// It's guaranteed that at this point your updateUserInfo action is handled and state tree is updated
dispatch(actions.userInfoUpdated(userInfo.username))

Новое действие «userInfoUpdated», которое вы затем обрабатываете в промежуточном программном обеспечении с избыточностью, выполняя вещь window.location.href = '...'.

1
WTK

Если вы вернете обещание fetch от своих фанатов, то вы можете продолжить цепочку обещаний от вызывающей стороны. Изменил код, предполагая, что updateUserInfo возвращает обещание получения:

return function(dispatch) {
  return fetch('https://backendserver.com:8080/creds', configuration)
  .then(response => response.json())
  .then(response => {
    //Would like to finish this dispatch completely before start executing window.location.href ='http://localhost:3005/#/Home'
    dispatch(actions.updateUserInfo(userInfo.username))
     .then(() => {
       window.location.href ='http://localhost:3005/#/Home'
     })
  })
  .catch((error) => {
    console.log("Error: ", error)
  })
}

Но я бы переместил вызов второго блока (updateUserInfo) в компонент React, поскольку первый блок (loggingIn) выполняет слишком много операций imo. Принцип единой ответственности и все такое.

1
Rick Jolly

Способ сделать это, не требующий ручной подписки на магазин и не требующий промежуточного программного обеспечения (как предлагают другие ответы), может быть следующим:

Разбавление:

function userReducer (state={ doneUpdating: false, userData: null }, action) {
  if (action.type === 'UPDATE_USER_INFO') { // this is the action dispatched by updateUserInfo
    return {  ...state, userData: action.payload, doneUpdating: true }
  }
}

Составная часть:

class YourComponent {
  componentWillReceiveProps (nextProps) {
    if (!this.props.doneUpdating && nextProps.doneUpdating) {
      window.location.href ='http://localhost:3005/#/Home'
    }
  }

  // Rest of your component methods here...
}

function mapStateToProps (state) {
  return { doneUpdating: state.userReducer.doneUpdating }
}

connect(mapStateToProps)(YourComponent)

В основном, после того как вы закончили обновление состояния, вы устанавливаете флаг. Ваш компонент (связанный с Redux) считывает этот флаг из состояния, и в componentWillReceiveProps вы обнаруживаете изменение и реагируете (каламбур предназначен :)) соответственно. В зависимости от вашего случая вам может потребоваться выполнить ту же логику проверки/перенаправления в componentWillMount. Это необходимо, если вам необходимо отправить действие обновления пользователя, когда ваш компонент еще не смонтирован. В этом случае флаг doneUpdating может стать истинным до того, как компонент будет смонтирован, и componentWillReceiveProps не будет вызываться.

0
fabio.sussetto

Поместите свой window.location.href ='http://localhost:3005/#/Home' в свой обработчик подписки. И убедитесь, что вы подписались на событие:

constructor(props, children)
{
    TheStore.subscribe( this.listenForDispatch.bind( this ) );
}

listenForDispatch()
{
    //Check the state is what you want
    if ( TheStore.getState().someProp == "somevalue" )
    {
        //Call it here!
        window.location.href ='http://localhost:3005/#/Home'
    }
}

Правка: Прежде чем вы начнете использовать Redux в своем коде, вам нужно прочитать их документацию и учебное пособие . subscribe является одним из основных способов использования Redux.

0
Don Rhummy