简体   繁体   English

自定义钩子等待来自 useEffect 钩子的回调

[英]Custom hook to await callback from useEffect hook

I have a web application, iwth an instance of a keycloack.js, where i tried to use a custom hook, to fetch a userprofile, before the UI renders.我有一个 web 应用程序,有一个 keycloack.js 的实例,我试图在 UI 呈现之前使用自定义钩子来获取用户配置文件。 The reason for that, is that the actual application requires, some information in localStorage before the ui should render.这样做的原因是实际应用程序需要在 ui 呈现之前在 localStorage 中的一些信息。

Here is the logic i have tried to implement in my App.js component这是我尝试在App.js组件中实现的逻辑

import React, {Suspense} from 'react';
import 'bootstrap/dist/css/bootstrap.css';
import 'appkit-react/style/appkit-react.default.css';
import PageHub from './Components/Navigation/PageHub';
import Spinner from './Components/Shared/Spinner';
import LoadUserProfile from './_helpers/hooks/loadUserProfile'
import './i18n';

function App(props) {


  const [loading, error] = LoadUserProfile(props.keycloak)
  console.log(props)
  if(loading){
    return <Spinner />
  }
  if(error){
    console.log(error)
    return <div>Error occured!!</div>
  }
  console.log(loading)
  console.log(error)
  return (
      <Suspense fallback={<Spinner/>}>
        <PageHub/>
      </Suspense>
  );
}

export default App;

and the LoadUserProfile hook looks like this. LoadUserProfile钩子看起来像这样。

import React, { useState, useEffect } from 'react';
import Spinner from '../../Components/Shared/Spinner';

function LoadUserProfile(keycloak){
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState({});

    useEffect(() =>{
        setLoading(true)
        keycloak.loadUserProfile().success((profile) => {
            console.debug('Loaded profile ' + profile);
            localStorage.setItem("firstName", keycloak.profile.firstName);
            localStorage.setItem("lastName", keycloak.profile.lastName);
            localStorage.setItem('GUID', keycloak.profile.attributes.guid[0])
            setLoading(false)
        }).error(() => {
            console.error('Failed to load profile')
            setLoading(false)
            setError({"error": "No user found"})
        }, [keycloak, loading, error]);

    })


    return [loading, error]

}
export default LoadUserProfile;

right now it goes into an infinite loop.现在它进入了一个无限循环。

So first of all you must rename your custom hook to useLoadUserProfile as recommended in the React Documentation so that React would be able to automatically check for violations of rules of Hooks.因此,首先您必须按照React 文档中的建议将自定义钩子重命名为useLoadUserProfile ,以便 React 能够自动检查是否违反了钩子规则。 The infinite loop is caused by the inclusion of the loading and error states in your dependency array.无限循环是由您的依赖项数组中包含加载错误状态引起的。 Whenever you make a call to 'setMyState' in this case setLoading or setError每当您在这种情况下调用“setMyState”时, setLoadingsetError

  1. React reruns your custom hook again and returns updated loading or error states React 再次重新运行您的自定义钩子并返回更新的加载错误状态
  2. The useEffect hook is then run again and calls setLoading or setError which causes React to run your function again.... hence the infinite loop.然后再次运行 useEffect 钩子并调用setLoadingsetError ,这会导致 React 再次运行您的函数......因此无限循环。

So to fix this you must remove the loading and error states from your dependency array.因此,要解决此问题,您必须从依赖项数组中删除加载错误状态。 The Rule of thumb is:经验法则是:
if you specify the dependency array, all values from inside your component that are used by the effect must be there.如果指定依赖项数组,则效果使用的组件内部的所有值都必须存在。 Including props, state, functions — anything in your component.包括 props、state、functions——组件中的任何东西。 ie never lie about your dependencies.即永远不要对您的依赖项撒谎。

In your case your useEffect hook does not even depend on your loading or error states.在您的情况下,您的 useEffect 钩子甚至不依赖于您的加载错误状态。 So they shouldn't be in the dependency array in the first place!所以它们一开始就不应该在依赖数组中!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM