Асинхронный бесконечный цикл useEffect

  const [allCases, setAllCases] = useState([])
  const [myCases, setMyCases] = useState([])
  const [sharedCases, setSharedCases] = useState([])
  const [favoriteCases, setFavoriteCases] = useState([])


useEffect(()=> {
    getData(_id).then(res => {
      const favoriteIds = res.data.find(i => i._id === _id).cases.map(x => {
        return x._id
      })
      setAllCases(res.cases.map(x => {
        if (favoriteIds.includes(x._id)) {
          return { ...x, isfavorite: true }
        }
        return { ...x, isfavorite: false }
      }))
      allCases && setSharedCases(allCases.filter(x => x.creator._id !== user._id))
      allCases && setMyCases(allCases.filter(x => x.creator._id === user._id))
      allCases && setFavoriteCases(allCases.filter(x => x.isfavorite))
    })

  }, [])

Здравствуйте, у меня проблема с бесконечным циклом. Если я включаю скобки, мои отфильтрованные случаи не заполняются. Если я добавлю еще один useEffect, я столкнусь с бесконечным циклом, хотя я не меняю allCases. (интересно, почему)

Как я могу решить эту асинхронную проблему?


person John    schedule 24.01.2020    source источник
comment
allCases не будет обновлено вовремя, чтобы вы могли использовать значения в этом вызове эффекта. Вам придется использовать второй useEffect. Что касается того, почему второй вызывал бесконечный цикл, я не могу сказать, не видя попытки. Возможно, вы использовали ссылку на массив как зависимость? }, [allCases])?   -  person Brian Thompson    schedule 24.01.2020


Ответы (2)


Одним из простых способов обойти эту проблему было бы вызвать другие сеттеры useState с локальной переменной вместо состояния. Затем вы можете обновить состояние allCases с помощью той же переменной, и вам не придется работать с асинхронными функциями.

useEffect(()=> {
  getData(_id).then(res => {
    const favoriteIds = res.data.find(i => i._id === _id).cases.map(x => {
      return x._id
    })

    // Save it to a local variable so that we have the value immediately
    const newAllCases = res.cases.map(x => {
      if (favoriteIds.includes(x._id)) {
        return { ...x, isfavorite: true }
      }
      return { ...x, isfavorite: false }
    })

    // Use the local variable to update state
    setSharedCases(newAllCases.filter(x => x.creator._id !== user._id))
    setMyCases(newAllCases.filter(x => x.creator._id === user._id))
    setFavoriteCases(newAllCases.filter(x => x.isfavorite))

    // Set the state for allCases
    setAllCases(newAllCases)
  })
}, [])
person Brian Thompson    schedule 24.01.2020
comment
Спасибо! мне пришлось немного отредактировать, добавив еще один эффект использования и сославшись на allCases. - person John; 24.01.2020
comment
useEffect(()=› { setAllCases(newAllCases) }) }, []) useEffect(()=› { setSharedCases(allCases.filter(x =› x.creator._id !== props.user._id)) setMyCases (allCases.filter(x => x.creator._id === props.user._id)) setFavoriteCases(allCases.filter(x => x.isfavorite)) }, [allCases]) - person John; 24.01.2020

allCases в useEffect не устанавливается до того, как вы установите sharedCases и другие. Кроме того, с [] в useEffect функция будет вызываться только при загрузке компонента. Таким образом, другие ваши значения состояния не будут установлены.

Я бы предложил иметь отдельный useEffect с [allCases] и установить все остальные значения там. Что-то вроде ниже

useEffect(()=> {
    getData(_id).then(res => {
      const favoriteIds = res.data.find(i => i._id === _id).cases.map(x => {
        return x._id
      })
      setAllCases(res.cases.map(x => {
        if (favoriteIds.includes(x._id)) {
          return { ...x, isfavorite: true }
        }
        return { ...x, isfavorite: false }
      }))
    })
  }, [])

useEffect(() => {
      // do filter and set the state
}, ['allCases'])
person Anuj    schedule 24.01.2020