ReactJS - componentDidUpdate () должен обновить два значения перед одним действием - PullRequest
0 голосов
/ 06 февраля 2020

В моем ReactJS компоненте я выполняю запрос токена на внешний API, а затем должен передать этот токен и мой userId в качестве аргументов для запроса axios. Это мой код:

import React, { Component } from 'react';
import axios from 'axios';
import Credentials from './spotify-auth.js'
import './Spotify.css'


class SpotifyAuth extends Component {  
  constructor (props) {
    super(props);
    this.state = {
      isAuthenticatedWithSpotify: false,
      menu: this.props.userId.menu
    };
    this.state.handleRedirect = this.handleRedirect.bind(this);
  };

  componentDidUpdate() {
      this.getFeatures(); // <------- axios method, see below
  }

  generateRandomString(length) {
    let text = '';
    const possible =
      'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    for (let i = 0; i < length; i++) {
      text += possible.charAt(Math.floor(Math.random() * possible.length));
    }
    return text;
    } 

  getHashParams() {
    const hashParams = {};
    const r = /([^&;=]+)=?([^&;]*)/g;
    const q = window.location.hash.substring(1);
    let e = r.exec(q);
    while (e) {
      hashParams[e[1]] = decodeURIComponent(e[2]);
      e = r.exec(q);
    }
    return hashParams;
  }

  componentDidMount() {
    //if (this.props.isAuthenticated) {
    const params = this.getHashParams();

    const access_token = params.access_token;
    const state = params.state;
    const storedState = localStorage.getItem(Credentials.stateKey);
    localStorage.setItem('spotifyAuthToken', access_token);
    localStorage.getItem('spotifyAuthToken');

    if (window.localStorage.getItem('authToken')) {
      this.setState({ isAuthenticatedWithSpotify: true });
    };
    if (access_token && (state == null || state !== storedState)) {
      alert('Click "ok" to finish authentication with Spotify');
    } else {
      localStorage.removeItem(Credentials.stateKey);
    }
    // DO STUFF WITH ACCEES TOKEN HERE
    this.props.onConnectWithSpotify(access_token); 
  };

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

Поэтому я применил следующее решение для защитного программирования:

  getFeatures(event) {
    const {userId, spotifyToken} = this.props
    if (!spotifyToken || !userId) {   // <-------------- HERE
      return;
    }
    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/${userId}/${spotifyToken}`;
    axios.post(url, data, {headers: headers})
      .then((res) => {
        console.log(data);
      })
      .catch((err) => {
      });
  };

  handleRedirect(event) {
    event.preventDefault()
    this.props.createMessage('You linked your Spotify account!', 'success');
    // get client features at authentication
    const params = this.getHashParams();
    const access_token = params.access_token;
    console.log(access_token);

    const state = this.generateRandomString(16);
    localStorage.setItem(Credentials.stateKey, state);

    let url = 'https://accounts.spotify.com/authorize';
    url += '?response_type=token';
    url += '&client_id=' + encodeURIComponent(Credentials.client_id);
    url += '&scope=' + encodeURIComponent(Credentials.scope);
    url += '&redirect_uri=' + encodeURIComponent(Credentials.redirect_uri);
    url += '&state=' + encodeURIComponent(state);
    window.location = url; 
  };

  render() {
      return (
        <div className="button_container">
        <h1 className="title is-3"><font color="#C86428">{"Welcome"}</font></h1>
            <div className="Line" /><br/>
              <button className="sp_button" onClick={(event) => this.handleRedirect(event)}>
                <strong>LINK YOUR SPOTIFY ACCOUNT</strong>
              </button>
        </div>
      )
  }
}
export default SpotifyAuth;

Теперь я не получаю неправильных вызовов с неопределенными значениями, но метод ax ios вызывается дважды, по одному на каждый обновление значения, что также нежелательно.


Если я положу getFeatures() внутри componentDidUpdate() и не пользуюсь условным условием, я получу:

  1. Неудачный запрос, где оба значения не определены
  2. Затем он обновляет userId, и я получаю неопределенное только для spotifyToken.
  3. Наконец, когда я нажимаю кнопку, она работает, оба значения обновляются, но затем запрос отправляется дважды.

Следуя принципу единой ответственности, я также попробовал следующее решение:

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

Но оно не работает.


Как это исправить?

...