如何按顺序使用 useEffect 运行?

How do I make useEffect run in order?

我的目标是获取我的 API 并在组件安装时对数据进行一些逻辑处理。当第一次提取调用成功时,我创建了另一个仅 运行 的 useEffect。我能够获取所有数据,但出现错误 "cannot read property 'length' of null"。如果我理解正确,第二个 useEffect 将在 companyData 更改时 运行。

错误:

 54 | useEffect(() => {
  55 |   async function organizeReviews() {
  56 |     let companyReviews = []
> 57 |       for(let i = 0; i < companyData.length; i++) {
     | ^  58 |         let reviewsForThisCo = []
  59 |         // loop through userReviews array
  60 |         for(let j=0; j < userReviews.length; j++) {

代码:

  const [averageRatings, setAverageRatings] = useState(null)
  const [companyData, setCompanyData] = useState(null)
  const [userReviews, setUserReviews] = useState([])
  const [organizedReviews, setOrganizedReviews] = useState(null)

  // Adding empty [] as second argument to run once component mounts
  useEffect(() => {
    async function getRatings() {
      try{
        const ratingRes = await fetch(process.env.REACT_APP_API_URL + '/api/v1/collected_reviews/')
        const ratingJson = await ratingRes.json()
        setAverageRatings(ratingJson.data)
      } catch(err) {
        console.log(err);
      }
    }

    async function getCompanyData() {
      try{
        const companyDataRes = await fetch(process.env.REACT_APP_API_URL + '/api/v1/companies/')
        const companyDataJson = await companyDataRes.json()
        setCompanyData(companyDataJson.data)
      } catch(err) {
        console.log(err);
      }
    }

    async function getCompanyReviews() {
      try{
        const reviewsRes = await fetch(process.env.REACT_APP_API_URL + '/api/v1/reviews/')
        const reviewsJson = await reviewsRes.json()
        setUserReviews(reviewsJson.data)
      } catch(err) {
        console.log(err);
      }
    }

    getRatings()
    getCompanyData()
    getCompanyReviews()

  }, [])

  useEffect(() => {
    async function organizeReviews() {
      let companyReviews = []
        for(let i = 0; i < companyData.length; i++) {
          let reviewsForThisCo = []
          // loop through userReviews array
          for(let j=0; j < userReviews.length; j++) {
            // if the user review id matches the company id
            if(userReviews[j].company.id === companyData[i].id) {
              reviewsForThisCo.push(userReviews[j])
            }
          }
            companyReviews.push(reviewsForThisCo)
        }
        setOrganizedReviews(companyReviews)
    }
    organizeReviews()
  }, [companyData])

the second useEffect will run whenever companyData changes.

没错。但它也总是 运行 在组件的初始安装上。所以你必须确保你的 companyData 存在于你的第二个 useEffect 中,因为它不会在第一次渲染时存在:

  useEffect(() => {

    if (companyData){
      async function organizeReviews() {
        let companyReviews = []
          for(let i = 0; i < companyData.length; i++) {
            let reviewsForThisCo = []
            // loop through userReviews array
            for(let j=0; j < userReviews.length; j++) {
              // if the user review id matches the company id
              if(userReviews[j].company.id === companyData[i].id) {
                reviewsForThisCo.push(userReviews[j])
              }
            }
              companyReviews.push(reviewsForThisCo)
          }
          setOrganizedReviews(companyReviews)
      }
      organizeReviews()
    } // if (companyData)

  }, [companyData])

现在它会在第一次渲染时 运行,但什么都不做,因为 companyData 还不存在。然后它会 运行 每次 companyData 改变。

请在第二个 useEffect 中使用 useRef(),如下所示

    const mounted = useRef();
      useEffect(() => {
      if (!mounted.current) {
        mounted.current = true;
      } else {
        async function organizeReviews() {
      let companyReviews = []
        for(let i = 0; i < companyData.length; i++) {
          let reviewsForThisCo = []
          // loop through userReviews array
          for(let j=0; j < userReviews.length; j++) {
            // if the user review id matches the company id
            if(userReviews[j].company.id === companyData[i].id) {
              reviewsForThisCo.push(userReviews[j])
            }
          }
            companyReviews.push(reviewsForThisCo)
        }
        setOrganizedReviews(companyReviews)
    }
    organizeReviews()
}
      }, [companyData])

If I understood correctly, the second useEffect will run whenever companyData changes.

是的,但是当第二个 useEffect 尝试将 .length 应用于 "companyData" 时,它仍然为空,并且您不能将 .length 应用于空变量。此错误在 "companyData" 更改

之前停止执行

你要做的就是将"companyData"初始化为一个空数组

const [companyData, setCompanyData] = useState([])

这是比较简单的方法,或者你可以复习里面第二个useEffect是"companyData"存在

useEffect(() => {
async function organizeReviews() {
  let companyReviews = []
    for(let i = 0; i < companyData.length; i++) {
      let reviewsForThisCo = []
      // loop through userReviews array
      for(let j=0; j < userReviews.length; j++) {
        // if the user review id matches the company id
        if(userReviews[j].company.id === companyData[i].id) {
          reviewsForThisCo.push(userReviews[j])
        }
      }
        companyReviews.push(reviewsForThisCo)
    }
    setOrganizedReviews(companyReviews)
}
if (companyData)
organizeReviews()
  }, [companyData])