Javascript 在我的数组中推多个对象会擦除数组中以前的所有对象(使用挂钩进行反应)

Javascript 在我的数组中推多个对象会擦除数组中以前的所有对象(使用挂钩进行反应),javascript,reactjs,axios,Javascript,Reactjs,Axios,我想在我的数组中推一个对象,在forEach的每个循环中, 但在每次循环中,我的数组似乎都变为空,所以我的数组中只有最后一个被推入的对象 我的代码中的这一行似乎不起作用: setSeriesLikedDetails([...seriesLikedDetails, dataSerieDetail.data]); 因为当我做这件事的时候 console.log("seriesLikedDetails ", seriesLikedDetails); 我总是在数组中有一个对象(最后一个推入的对象),

我想在我的数组中推一个对象,在forEach的每个循环中, 但在每次循环中,我的数组似乎都变为空,所以我的数组中只有最后一个被推入的对象

我的代码中的这一行似乎不起作用:

setSeriesLikedDetails([...seriesLikedDetails, dataSerieDetail.data]);
因为当我做这件事的时候

console.log("seriesLikedDetails ", seriesLikedDetails);
我总是在数组中有一个对象(最后一个推入的对象),而不是一个对象数组

以下是组件代码的一部分:

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);
      }
    });
  }

这很可能是因为在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));

  }

您将使用正确的新值更新状态一次。

这很可能是因为在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));

  }

您将使用正确的新值更新状态一次。

系列详细信息将在此处缓存,并且仅在组件重新加载时更新。由于在重新加载期间不会再次调用
loadSeriesLikedDetails()
,因此初始
seriesLikedDetails
仍然是一个空数组

让我们看一下内部发生了什么(您的代码):

  • 组件被渲染
    useffect()
    “启动并运行”
  • 正在进行Axios调用,然后调用
    setSeriesIkedDetails()
    seriesLikedDetails
    现在包含一个元素
  • 组件现在重新招标。重新检索组件时,
    loadSeriesLikedDetails()不是被称为
    系列喜欢的
没有改变
  • Axios调用将继续进行(从原始渲染调用),但是
    seriesLikedDetails
    的当前值仍然是空数组,因为这仍然发生在原始渲染中
  • 避免使用
    Promise.all
    ,因为您可能希望在更新到来时对UI进行顺序更新。在这种情况下,您可以将
    setSeriesIkedDetails
    与函数一起使用,以始终拉取当前值以更新它:

    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]);
    
    此外,您可能还希望在开始时重置阵列(或写入阵列,以便只获取尚未获取的电影/系列):


    请参阅部分文档。

    系列详细信息将在此处缓存,并且仅在组件重新加载时更新。由于在重新加载期间不会再次调用
    loadSeriesLikedDetails()
    ,因此初始
    seriesLikedDetails
    仍然是一个空数组

    让我们看一下内部发生了什么(您的代码):

    • 组件被渲染
      useffect()
      “启动并运行”
    • 正在进行Axios调用,然后调用
      setSeriesIkedDetails()
      seriesLikedDetails
      现在包含一个元素
    • 组件现在重新招标。重新检索组件时,
      loadSeriesLikedDetails()不是被称为
      系列喜欢的
    没有改变
  • Axios调用将继续进行(从原始渲染调用),但是
    seriesLikedDetails
    的当前值仍然是空数组,因为这仍然发生在原始渲染中
  • 避免使用
    Promise.all
    ,因为您可能希望在更新到来时对UI进行顺序更新。在这种情况下,您可以将
    setSeriesIkedDetails
    与函数一起使用,以始终拉取当前值以更新它:

    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]);
    
    此外,您可能还希望在开始时重置阵列(或写入阵列,以便只获取尚未获取的电影/系列):


    请参阅部分文档。

    完美,它现在可以与您编辑的答案一起使用!谢谢,如果它不能解释你最初的问题,弗兰克兹下面的答案更适合你的需要。好的,np,你能接受你的答案吗,因为我对另一个答案有一个问题:完美,它现在适用于你编辑的答案!谢谢,如果它不能解释你最初的问题,弗兰克兹下面的答案更适合你的需要。好的,np,你能让你的答案,因为我对另一个答案有一个问题:DMy回答交易和解释OP的范围问题,但这应该是怎么做的。你好,我试过你的答案,它非常适合电视节目,但对于电影,forEach在moviesLiked中每项完成2次(因为事实上我必须为电影和电视节目这样做)我在moviesLiked中有3项,但forEach是6次,而不是3次(每项2次)setMoviesLikedDetails(currDetails=>[…currDetails,dataMovieDetail.data]);发布您的更新代码。此外,请尝试使用
    currMovieDetails
    以避免名称重叠。@请参阅我的更新答案。由于@remix32的代码使用了
    Promise.all()
    并随后更新了所有内容,因此它将覆盖可能存在的任何细节。你可能想在
    loadSeriesLikedDetails()
    开始时重置数组。我发布了更新的代码,这与我为电影复制的系列是一样的。因此,在渲染中,我映射到moviesLikeDetails,我在doubleMy Response中得到了每一部电影,并解释了OP的范围问题,但这应该是如何做到的。您好,我尝试了您的答案,它对电视节目非常有效,但对于电影来说,forEach似乎在moviesLiked中每项做了2次(因为事实上我不得不这么做)