【问题标题】:modifying object inside useEffect() doesn't update the state在 useEffect() 中修改对象不会更新状态
【发布时间】:2020-07-21 22:18:20
【问题描述】:

我不熟悉 React 和 Hooks 的使用。我正在尝试从某个 API 中获取一个对象,对其进行转换(基于另一个 API 的结果)并更新 useEffect 挂钩中的状态。然而,当 DOM 被渲染时,对象的变换并没有反映出来。这是我的代码。

  useEffect(() => {
    let modified_movies = []
    axios.get(LOCAL_MOVIE_API)
      .then(res => {
        const movies = res.data.content;
        movies.map(async movie => {
          const response = await axios.get(_API,
            {
              params: {
                query: movieTitle,
                year: movie.movieYear
              }
            });
            const poster = response.poster; //add property to object
            const modified_movie = { ...movie, poster_url: poster };
            modified_movies.push(modified_movie)
        })
        setMovies(modified_movies) //
      })
  }, [])

我也没有就地修改对象,因此制作了对象的副本,但是 react 仍然没有使用修改的对象更新状态,并且新属性没有反映在视图中。我错过了一些明显的东西还是有更好的方法来实现这一点?

【问题讨论】:

    标签: promise axios


    【解决方案1】:

    与react无关。

    您的movies.map(async movie => {... 调用正在创建Promises,它将在您的setMovies 调用之后执行,因此modified_movies 数组将为空。所以需要等到map函数完成后,再设置状态。

    解决问题的一种方法:

    useEffect(() => {
        let modified_movies = []
        axios.get(LOCAL_MOVIE_API)
          .then(res => {
            const movies = res.data.content;
            const moviePromises = movies.map(async movie => await axios.get(_API,
                {
                  params: {
                    query: movieTitle,
                    year: movie.movieYear
                  }
                })
            ) // map all the calls into one array 
            Promise.all(moviePromises).then((allResponses) => {
                // allResponses will be an array of values, which you can map to your needs
                setMovies(allResponses) //
            })
          })
      }, [])
    

    这里有一些有用的文档:

    Promise.all

    Array.map

    【讨论】:

      【解决方案2】:

      这与 React 或 useEffect 无关。

      你只是遇到了 Promise 的问题。

      考虑这个例子:

      // ----------- YOUR   WAY --------------
      const getRandomValue = () => {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve(Math.random());
          }, 10);
        });
      };
      
      const movies = [1, 2, 3];
      
      const modified_movies = [];
      
      movies.map(async(movie) => {
        modified_movies.push(await getRandomValue());
      });
      
      console.log("modified movies with map", modified_movies);
      
      // ---------- One of correct ways -----------------
      
      const Movies = [1, 2, 3];
      
      const modifiedMovies = [];
      
      const getModifiedMovies = async() => {
        for (let movie in movies) {
          modifiedMovies.push(await getRandomValue());
        }
      
      };
      
      getModifiedMovies().then(() => {
        console.log("modified movies with for let", modifiedMovies);
      });

      第一种方法模拟你的方式,它总是返回一个空数组。

      第二种方法等待所有的承诺被解决,从而返回正确的。

      回到你的问题,我认为代码应该是这样的:

      axios.get(LOCAL_MOVIE_API)
        .then(async(res) => {
          const movies = res.data.content;
          for (const movie of movies) {
            const response = await axios.get(_API, {
              params: {
                query: movieTitle,
                year: movie.movieYear
              }
            });
            const poster = response.poster; //add property to object
            const modified_movie = { ...movie,
              poster_url: poster
            };
            modified_movies.push(modified_movie);
          }
          setMovies(modified_movies);
        });
      

      【讨论】:

        【解决方案3】:

        您需要提供应该触发哪个状态更改 useEffect,如下所示:

        useEffect(() => {
              // your logic here
              })
          }, [theStateWhichChanged])
        

        【讨论】:

        • useEffect 已经第一次被触发,所以这对我来说不是问题。
        【解决方案4】:

        您的依赖数组为空,这意味着 useEffect 中的代码在组件挂载时执行,并且仅在此一次执行。 对我来说,代码看起来过于复杂并且缺少部分(movieTitle、movie.movi​​eYear 是从哪里来的?)。我建议您将您的请求拆分为 useEffect 中的函数,以便您自己更清楚。

        如果你有一个效果依赖的状态(例如另一个状态),那么你需要将 i 添加到你的依赖数组中:

        React.useEffect(() => {
          // your code here
        }, [movies])
        

        【讨论】:

          猜你喜欢
          • 2020-01-25
          • 2020-11-06
          • 2021-06-25
          • 2022-01-21
          • 2023-01-26
          • 2021-07-03
          • 1970-01-01
          • 1970-01-01
          • 2021-10-02
          相关资源
          最近更新 更多