【问题标题】:Custom hook not triggering component rerender despite changes in state尽管状态发生了变化,但自定义钩子不会触发组件重新渲染
【发布时间】:2020-12-02 06:48:38
【问题描述】:

上下文:我有一个自定义挂钩来获取 Firestore 文档。它监视文档更改,然后返回它和加载状态。我在另一个组件中使用了这个钩子。

问题:更改挂钩返回的状态值(loadingdocument)不会触发组件使用挂钩重新呈现并查看更新的值。

我的发现:其他自定义钩子可以工作并触发渲染,所以useDocument 钩子肯定有问题。如果另一个钩子触发了重新渲染,那么loading 才会最终更新。 loadingdocument 的值确实在钩子中按预期更新,但组件的重新渲染仍然不会触发。

重要说明: useFirebase() 是在 useDocument 内调用的钩子,其状态使用 constate 库提升到上下文中。所以从技术上讲,这个钩子是一些提供者的消费者,它位于跟踪 firebase 库的树的上层。这是为了避免不必要的网络调用。


export function useDocument() {
  const { auth, firestore } = useFirebase() // asynchronously fetches firebase modules
  const [loading, setLoading] = useState(true)
  const [document, setDocument] = useState()

  let unsubscribe = null

  

  useEffect(() => {
    let unsubscribe = null
    const watchDocument = () =>
      params?.query.onSnapshot(
        (doc) => {
          setDocument(doc.data() as T | undefined)
          setLoading(false)
        },
        (err) => {
          console.log(err)

          setError(err.message)
        }
      )
    if (firestore && auth?.currentUser) {
      unsubscribe = watchDocument()
    }
    return () => {
      unsubscribe && unsubscribe()
    }
  }, [firestore, auth?.currentUser])

  return {
    document,
    loading
  }
}

const MyComponent = () => {
  const {document, loading} = useDocument()
  console.log(loading) // changes to "loading" doesn't trigger rerender of this component
}

【问题讨论】:

    标签: javascript reactjs firebase react-hooks react-context


    【解决方案1】:

    这个sn-p的错误很少,主要是变量unsubscribe总是undefined,因为它甚至不在useEffect的范围内。

    这可能是一个有效的修复(从未使用过 firebase,仅通过查看代码):

    export function useDocument() {
      const { auth, firestore } = useFirebase();
      const [loading, setLoading] = useState(true);
      const [document, setDocument] = useState();
    
      useEffect(() => {
        const watchDocument = async () => {
          const unsubscribe = await params?.query.onSnapshot(
            (doc) => {
              setDocument(doc.data());
              setLoading(false);
            },
            (err) => {
              console.log(err);
              setError(err.message);
            }
          );
        };
    
        let unsubscribe = null;
        if (firestore && auth) {
          unsubsribe = watchDocument();
        }
        return () => {
          unsubscribe?.();
        };
      }, [firestore, auth]);
    
      return {
        document,
        loading,
      };
    }
    
    const MyComponent = () => {
      const { document, loading } = useDocument();
      console.log(loading);
    };
    

    【讨论】:

    • 在深入挖掘并看到我确实在错误的地方定义了取消订阅后,我删除了我的原始评论。我用正确的代码更新了我的问题。谢谢!重新渲染行为最终成为一个参考问题。我还意识到我在问题中删除了太多代码,因此我对其进行了更新以反映问题所在。
    【解决方案2】:

    所以问题是依赖auth?.currentUserauth 本身在状态更改时会正确触发重新渲染。问题似乎是无法检测到auth?.currentUser 中的更改。

    我的假设是,这是因为 auth 是被跟踪的内容,即使 currentUser 由 firebase 库更新,对 auth 的引用也不会改变。我最终将currentUser 移动到了它自己的useState 中,现在组件正确地重新渲染了。

    【讨论】:

      猜你喜欢
      • 2022-11-04
      • 2016-07-07
      • 2021-06-21
      • 1970-01-01
      • 2021-07-09
      • 2020-10-29
      • 1970-01-01
      • 1970-01-01
      • 2020-01-26
      相关资源
      最近更新 更多