Нажатие многих объектов в моем массиве стирает все предыдущие объекты массива (React with Hooks) - PullRequest
0 голосов
/ 20 октября 2019

Я хочу выдвинуть объект в моем массиве, в каждом цикле forEach, но в каждом цикле кажется, что мой массив становится пустым, поэтому в мой массив вставляется только последний объект,

Похоже, эта строка из моего кода не работает:

setSeriesLikedDetails([...seriesLikedDetails, dataSerieDetail.data]);

, потому что когда я делаю

console.log("seriesLikedDetails ", seriesLikedDetails);

вместо массива объектов, у меня всегда есть 1 объект вмассив (последний вставленный) ..

Вот часть кода компонента:

function Likes(props) {
  const [moviesLiked, setMoviesLiked] = useState([]);
  const [seriesLiked, setSeriesLiked] = useState([]);
  const [moviesLikedDetails, setMoviesLikedDetails] = useState([]);
  const [seriesLikedDetails, setSeriesLikedDetails] = useState([]);

  useEffect(() => {
    loadMoviesLikedDetails();
    loadSeriesLikedDetails();
  }, [moviesLiked, seriesLiked]);

  async function loadMoviesLikedDetails() {
    setMoviesLikedDetails([]);
    moviesLiked.forEach(async movie => {
      try {
        const dataMovieDetail = await axios.get(
          `https://api.themoviedb.org/3/movie/${movie}?api_key=381e8c936f62f2ab614e9f29cad6630f&language=fr`
        );
        console.log("MovieDetail ", dataMovieDetail.data);
        setMoviesLikedDetails(movieDetails => [
          ...movieDetails,
          dataMovieDetail.data
        ]);
      } catch (error) {
        console.error(error);
      }
    });
  }

  async function loadSeriesLikedDetails() {
    setSeriesLikedDetails([]);
    seriesLiked.forEach(async serie => {
      try {
        const dataSerieDetail = await axios.get(
          `https://api.themoviedb.org/3/tv/${serie}?api_key=381e8c936f62f2ab614e9f29cad6630f&language=fr`
        );
        console.log("SerieDetail ", dataSerieDetail.data);
        setSeriesLikedDetails(serieDetails => [
          ...serieDetails,
          dataSerieDetail.data
        ]);
      } catch (error) {
        console.error(error);
      }
    });
  }

Ответы [ 2 ]

1 голос
/ 20 октября 2019

seriesLikedDetails кэшируется здесь и обновляется только при повторном рендеринге компонента. Поскольку loadSeriesLikedDetails() не вызывается во время повторного рендеринга, ваш начальный seriesLikedDetails остается пустым массивом.

Давайте рассмотрим, что происходит внутри (Ваш код):

  • Компонент оказывается. useEffect() запускается и запускается.
  • Осуществляются вызовы Axios, а затем выполняется вызов setSeriesLikedDetails(). seriesLikedDetails теперь содержит один элемент.
  • Компонент теперь перерисовывается. Когда компонент перерисовывается, loadSeriesLikedDetails(); - это НЕ , называемый seriesLiked, не изменился.
  • Вызовы Axios продолжают выполняться (Вызывается из исходного рендера), но текущийзначение seriesLikedDetails остается пустым массивом, потому что это все еще происходит в исходном рендере.

Избегайте использования здесь Promise.all, так как вы можете захотеть делать последовательные обновления вашего пользовательского интерфейса по мере поступления обновленийВ этом случае вы можете использовать setSeriesLikedDetails с функцией, чтобы всегда получать текущее значение для его обновления:

function Likes(props) {
  const [moviesLiked, setMoviesLiked] = useState([]);
  const [seriesLiked, setSeriesLiked] = useState([]);
  const [moviesLikedDetails, setMoviesLikedDetails] = useState([]);
  const [seriesLikedDetails, setSeriesLikedDetails] = useState([]);

  useEffect(() => {
    loadSeriesLikedDetails();
  }, [seriesLiked]);

  useEffect(() => {
    console.log("seriesLikedDetails ", seriesLikedDetails);
  }, [seriesLikedDetails]);

  async function loadSeriesLikedDetails() {
    seriesLiked.forEach(async serie => {
      try {
        const dataSerieDetail = await axios.get(
          `https://api.themoviedb.org/3/tv/${serie}?api_key=381e8c936f62f2ab614e9f29cad6630f&language=fr`
        );
        console.log("SerieDetail ", dataSerieDetail.data);
        setSeriesLikedDetails(currSeriesDetails => [...currSeriesDetails, dataSerieDetail.data]);
      } catch (error) {
        console.error(error);
      }
    });
  }

Это так же просто, как передать функцию:

setSeriesLikedDetails(currSeriesDetails => [...currSeriesDetails, dataSerieDetail.data]);

Кроме того, вы можете также сбросить массив в начале (или запишите его, чтобы получать только те фильмы / сериалы, которые вы еще не загрузили):

async function loadSeriesLikedDetails() {
     setMoviesLikedDetails([]); // Reset array

См. Функциональные обновления кроме документов.

1 голос
/ 20 октября 2019

Это наиболее вероятно, потому что в обратном вызове forEach seriesLikedDetails всегда является одной и той же ссылкой, тогда как setSeriesLikedDetails изменяет фактический массив, который вы хотите отслеживать.

Поэтому, когда вы на последней итерации forEach просто добавляетеПоследнее значение в исходный массив и установить его в качестве текущего массива.

Таким образом, вместо этого:

async function loadSeriesLikedDetails() {
    const newArray = [...seriesLikedDetails];
    const promises = seriesLiked.map(async serie => {
      try {
        const dataSerieDetail = await axios.get(
          `https://api.themoviedb.org/3/tv/${serie}?api_key=381e8c936f62f2ab614e9f29cad6630f&language=fr`
        );
        console.log("SerieDetail ", dataSerieDetail.data);

        newArray.push(dataSerieDetail.data);
      } catch (error) {
        console.error(error);
      }
    });
    Promise.all(promises).then(()=>setSeriesLikedDetails(newArray));

  }

Вы обновите состояние один раз с правильным новым значением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...