ReactJS - ax ios запрос в componentDidUpdate () - PullRequest
1 голос
/ 31 января 2020

Я узнал, что в Reactjs:

componentDidUpdate() вызывается сразу после обновления. Этот метод не вызывается для начального рендеринга.

У меня есть этот метод в моем компоненте, который отправляет сетевой запрос с помощью axio:

getFeatures(event) {
    const data = {
      spotify_token: this.props.spotifyToken
    };
    var headers = {
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': true,
        Authorization: `Bearer ${window.localStorage.authToken}`
      }
    const url = `${process.env.REACT_APP_WEB_SERVICE_URL}/features/${this.props.userId}/${this.props.spotifyToken}`;
    axios.post(url, data, {headers: headers})
      .then((res) => {
        console.log(data);
      })
      .catch((err) => {
      });
  };

Вызывается метод getFeatures() после получения реквизита, например, так:

componentDidUpdate(){
  this.getFeatures();
}

Однако вызов завершается, прежде чем он работает, он выдает ошибку 404 и неправильно сформированный запрос POST, в то время как оба необходимых реквизита еще не были обновлены до их значений:

  1. POST http://localhost/features//undefined 404 (NOT FOUND)
  2. XHR finished loading: POST "http://localhost/features/1/undefined"

Как исправить эти ошибки до того, как они заработают?

Ответы [ 4 ]

1 голос
/ 31 января 2020

Согласно документам, вы должны сравнить текущие реквизиты с предыдущими реквизитами, прежде чем вызывать побочные эффекты, такие как вызовы API или обновления состояния.

Не могли бы вы обновить componentDidUpdate до чего-то подобного и повторить попытку -

componentDidUpdate(prevProps) {
  // Typical usage (don't forget to compare props):
  if (this.props.spotifyToken !== prevProps.spotifyToken) {
    this.getFeatures(this.props.spotifyToken)
  }
}

Кроме того, вы должны добавить проверку для this.props.spotifyToken для пустого или неопределенного значения и не выполнять вызов API.

1 голос
/ 31 января 2020

Вы захотите добавить некоторые условные выражения к вашему componentDidUpdate, чтобы гарантировать, что getFeatures не вызывается каждый раз, когда изменяется проп или состояние. После первоначального монтирования каждое отдельное изменение будет вызывать это, и, вероятно, именно поэтому вы получаете странные ошибки с undefined в URL.

componentDidUpdate(prevProps){
  const { spotifyToken, userId } = prevProps;

  if (spotifyToken && userId && (spotifyToken !== this.props.spotifyToken || userId !== this.props.userId)) {
    this.getFeatures();
  }
}

Так как в конечном итоге это удается, это заставляет меня думать, что либо spotifyToken или userId обновляются после первоначального монтирования компонента, но один или другой undefined, пустая строка или что-то другое неверно.

FWIW, с использованием последней версии React с крючками помогает привести в порядок это очень. Вы можете просто добавить свои зависимости после useEffect, и это позаботится о грязной логике c этого условного выражения.

useEffect(() => {
  if (spotifyToken && userId) getFeatures();
}, [spotifyToken, userId]);
1 голос
/ 31 января 2020

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

Простым решением было бы применить принципы защитного программирования к вашему getFeatures() методу:

getFeatures(spotifyToken, userId) {

  /* If required props are not defined, early exit as the request
     cannot be completed */
  if (!spotifyToken || !userId) {
    return;
  }

  /* The required props are present so attempt network request */
  var headers = {
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': true,
    Authorization: `Bearer ${window.localStorage.authToken}`
  }

  const url = `${process.env.REACT_APP_WEB_SERVICE_URL}/features/${userId}/${spotifyToken}`;
  axios.post(url, data, {
      headers: headers
    })
    .then((res) => {
      console.log(data);
    })
    .catch((err) => {
      console.error(err);
    });
}

componentDidUpdate(prevProps) {
    const { spotify_token, userId } = this.props;

    if(prevProps.spotify_token !== spotify_token || prevProps.userId !== userId) {
        /* If a change occurred in token or user id, attempt to get 
        features */
        this.getFeatures(spotify_token, userId);
    }
}

Эти изменения означают, что как только все необходимые данные prop будут присутствовать, ваш сетевой запрос будет быть выполненным.

Если, например, реквизиты spotify_token и userId будут предоставлены позднее (ie после взаимодействия с пользователем, например, нажатием кнопки), то будет вызван метод componentDidUpdate() и сетевой запрос будет выполнен.

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

1 голос
/ 31 января 2020

Это потому, что ваши реквизиты spotifyToken и userId не готовы, когда компонент обновляется и вызывается getFeatures. Проверьте, определены ли они.

Кроме того, вызывать API на каждое обновление пользовательского интерфейса не очень хорошая идея. Сделайте некоторую проверку действительности так:

componentDidUpdate(prevProps) {
  const { spotifyToken, userId } = this.props;
  if (spotifyToken && userId && (spotifyToken !== prevProps.spotifyToken || userId !== prevProps.userId)) {
    this.getFeatures();
  }
}
...