首页 > 解决方案 > 在渲染之前重置 React 状态

问题描述

我正在构建一个使用 TMDB Api 的 Web 应用程序。我有以下代码可以获取有关电视节目的所有信息

export const useShowInfoFetch = ({showId}) => {

  const [data, setData] = useState({})
  const [loading, setLoading] = useState(false)
  const [_error, _setError] = useState(false)

  const fetchShowInfo = useCallback(() => {
    setLoading(true)

    try {
      axios.get(getShowInfo(showId))
        .then(response => {
          setData(response.data)
        })
    } catch (error) {
      _setError(true)
    } finally {
      setLoading(false)
    }
  }, [showId])

  useEffect(() => {
    fetchShowInfo()
  }, [fetchShowInfo])

  return [data, loading, _error]
}

获取的所有信息都显示在页面中,该页面还具有带有react-router-dom 的链接。这些链接转到另一个电视节目页面。问题是,当我在一个包含 X 季数量的电视节目的页面中单击一个具有较少季节的电视节目时,我所在页面的季节会持续一段时间。因此,当我获取每个季节的信息时,我在页面中得到了一个 404,它的季节较少。

这是错误的屏幕截图

在此处输入图像描述

橙色圆圈是它显示的内容,因为我单击了季节较少的电视节目。如您所见,上一页中的季节持续了一段时间,并且由于 The Alienist 只有 2 个季节(不是 9 个),我得到了 404。您还可以注意到后者,显示了正确的季节数量。

我试图在useEffect挂钩中添加一个清理方法。像这样的东西:

useEffect(() => {
    fetchShowInfo()
    
    return function cleanup() {
      setData({})
    }
  }, [fetchShowInfo])

但这没有用。

我知道在当时的 Axios 承诺之后我可以通过捕获来处理这个问题,但我想弄清楚为什么会发生这种情况,并用一个好的解决方案来解决这个问题,而不是避免它。

欢迎任何帮助,如果需要,我可以与所有代码共享存储库。

编辑:

为了显示类似的电影,我使用了另一个自定义钩子

export const useSimilarFetch = (elementType, elementId) => {

  const [similarElements, setSimilarElements] = useState({elements: []})
  const [similarLoading, setSimilarLoading] = useState(false)
  const [_error, _setError] = useState(false)

  const fetchSimilarElements = useCallback(async (endpoint) => {
    console.log(">>> fetching similar elements <<<")
    setSimilarLoading(true)

    try {
      await axios.get(endpoint)
        .then(response => {
          setSimilarElements(() => ({
            elements: [...response.data.results],
            currentPage: response.data.page,
            totalPages: response.data.total_pages
          }))
        })
    } catch (error) {
      _setError(true)
    } finally {
      setSimilarLoading(false)
    }
  }, [])

  useEffect(() => {
    fetchSimilarElements(getSimilar(elementType, elementId));
  }, [fetchSimilarElements, elementType, elementId])

  return [{similarElements, similarLoading, _error}, fetchSimilarElements]
}

然后,在我的 ShowInfoComponent 中,我调用所有需要的钩子,如下所示:

const {showId} = useParams()
const [data, loading, _error] = useShowInfoFetch({showId})
const [{similarElements, similarLoading}] = useSimilarFetch("tv", showId)

谢谢。

标签: javascriptreactjsreact-routerreact-hooksjsx

解决方案


到时间showId变化时,data必须等待一个额外的渲染周期,因此showId即使data尚未获取,也已使用。UI 既依赖于showIdand data,又data依赖于showId. data解决此问题的一种方法可能是让您的 UI单独依赖。身份证呢?例如添加它data。我们只是想避免去同步。

像这样的东西:

export const useShowInfoFetch = ({showId}) => {

  const [data, setData] = useState({})
  const [loading, setLoading] = useState(false)
  const [_error, _setError] = useState(false)

  const fetchShowInfo = useCallback(() => {
    setLoading(true)

    try {
      axios.get(getShowInfo(showId))
        .then(response => {
          setData({ id: showId, info: response.data})
        })
    } catch (error) {
      _setError(true)
    } finally {
      setLoading(false)
    }
  }, [showId])

  useEffect(() => {
    fetchShowInfo()
  }, [fetchShowInfo])

  return [data, loading, _error]
}

然后用于data.id建立您的链接。如果 response.data已经包含 id,那么更好的是,使用它。

当然,这只是一个例子,但希望你能明白这一点。


推荐阅读