【问题标题】:Detecting if Apollo has finished configuration before allowing queries在允许查询之前检测 Apollo 是否已完成配置
【发布时间】:2021-07-26 09:36:53
【问题描述】:

我有一个具有以下顶级结构的 React SPA。我使用 Auth0 进行身份验证,使用 Apollo Client 进行查询,使用 React Context 提供全局状态。

我遇到的问题是,在 Apollo 客户端完成其标头的配置(即,通过 Auth0 插入令牌)之前,在我的全局状态下执行的查询正在执行。

有没有办法(也许使用 useApolloClient 钩子来判断 Apollo 在其 authLink 中是否有令牌?或者另一种方式来实现延迟初始化 Global State 直到其父组件 AuthorizedApolloProvider 完成的目标?

<BrowserRouter>
  <Auth0ProviderWithHistory>
    <AuthorizedApolloProvider>
      <GlobalState>
        <App />
      </GlobalState>
    </AuthorizedApolloProvider>
  </Auth0ProviderWithHistory>
</BrowserRouter>

在 AuthorizedApolloProvider 中,我通过在所有查询中插入令牌来为 Apollo 设置上下文,如下所示:

const AuthorizedApolloProvider = ({children}) => {

  const { getAccessTokenSilently } = useAuth0()

  const httpLink = createHttpLink ({
    uri: uriGQL, // a config parameter
  })
  
  const authLink = setContext(async () => {
    const token = await getAccessTokenSilently()
    console.log('Got the token..... ', token.substring(0, 10))
    return {
      headers: {
        authorization: token ? token : ""
      }
    }
  })

  let links = [authLink, httpLink]

  const client = new ApolloClient({
    link: ApolloLink.from(links),
    cache: new InMemoryCache({
      addTypename: false,
    }),
  })

  console.log('Rendering ApolloProvider')

  return(
    <ApolloProvider client={client}>
      {children}
    </ApolloProvider>
  )
}

接下来,在 Global State 中,我发送 GQL 查询以获取有关已登录用户的信息,如下所示:


const GlobalState = props => {

  const { user: auth0User, isLoading, isAuthenticated } = useAuth0()

  const client = useApolloClient()

  const [state, setState] = useState(initialState)

  const [ getUser, { loading, data, error }] = useLazyQuery(GET_USER)
  
  const history = useHistory()


  useEffect(async () => {

    // Has useAuth0 returned?
    if(isLoading===false) {
      console.log('isAuthenticated=', isAuthenticated)
      console.log('auth0User', auth0User)

      // Is authenticated?
      if(!isAuthenticated) {
        // If not authenticated...
        console.log('Not authenticated')
        localStorage.removeItem('user')
        setState({ ...state, loaded: true, user: null })
      }
      else {
        // If authenticated...
        // Check to see if user object is in local storage
        let user = await localStorage.getItem('user')
        if(user) {
          console.log('Authenticated, found user in local storage')
          // User found in local storage
          user = JSON.parse(user)
          setState({ ...state, loaded: true, user: user })
        }
        else {
          // User not found in local storage. Must fetch from server
          console.log('Authenticated, getting user from server')

          try {
            console.log('Calling getUser...')
            const result = await getUser()
          }
          catch (error) {
            console.log(error)
          }
        }
      }
    }

  }, [isLoading])

...

我遇到的问题是在 Apollo 客户端完成配置之前调用了 getUser 查询。

当我运行代码时,我看到下面的片段...

try {
   console.log('Calling getUser...')
   const result = await getUser()
}

...在以下...之前被执行

console.log('Got the token..... ', token.substring(0, 10))
    return {
      headers: {
        authorization: token ? token : ""
      }
    }

【问题讨论】:

    标签: auth0 apollo-client react-context


    【解决方案1】:

    您需要以阻塞方式等待getAccessTokenSilently 完成。您可以通过使用状态来实现这一点。

    const [token, setToken] = useState();
    
    useEffect(()=>{
     try {
      const token = await getAccessTokenSilently(); // you need this to finish before moving on
      setToken(token);
     } catch (e){
      //catch errors
     }
    }, []);
    
    if(!token) return '...loading'; //render loading component
    
    const authLink = setContext(() => {
     //token comes from state now & don't need await
    })
    
    const links = [authLink, httpLink];
    
    const client = new ApolloClient({
     link: ApolloLink.from(links),
     cache: new InMemoryCache({ addTypename: false })
    })
    
    return(
     <ApolloProvider client={client}>
      {children}
     </ApolloProvider>
    )
    

    我个人将我的 ApollClient、链接和其他相关的 ApolloConfig 放在不同的文件中,并传递一个令牌来清理一下。

    【讨论】:

    • 谢谢一百万。这解决了问题。我现在可以阻止全局状态的渲染,直到 Apollo 完成加载。
    猜你喜欢
    • 2014-09-11
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    • 2020-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多