React、Apollo 2、GraphQL、身份验证。登录后如何重新渲染组件

Posted

技术标签:

【中文标题】React、Apollo 2、GraphQL、身份验证。登录后如何重新渲染组件【英文标题】:React, Apollo 2, GraphQL, Authentication. How to re-render component after login 【发布时间】:2018-05-19 05:15:43 【问题描述】:

我有这个代码:https://codesandbox.io/s/507w9qxrrl

我不明白:

1) 如何重新渲染() Menu 组件后:

this.props.client.query(
  query: CURRENT_USER_QUERY,
  fetchPolicy: "network-only"
);

如果我 login() 我希望我的 Menu 组件重新渲染() 本身。但什么都没有。 只有当我点击 Home 链接时,它才会重新渲染()本身。我怀疑是因为我正在使用它来渲染它:

<Route component=Menu />

将它包含在 react-router 道具中。错了吗?

另外,如果在login() 之后检查菜单的this.props,我会永远看到loading: true。为什么?

2) 如何防止Menu组件在未认证的情况下查询(例如:localStorage中没有token);我在Menu 组件中使用了这段代码:

export default graphql(CURRENT_USER_QUERY)(Menu);

3) 这是正确的方法吗?

【问题讨论】:

&lt;Route component=Menu /&gt;这行代码我好像没找到?? 被评论是因为我试图不使用它。 @Dane,如果我删除该行并仅使用 &lt;Menu /&gt; 它根本不会重新渲染。 我重置了有问题的代码。 关于(2),您可以轻松跳过查询,如下所述:apollographql.com/docs/react/basics/queries.html#graphql-skip 【参考方案1】:

首先,让我回答您的第二个问题:您可以使用skip query option 跳过操作。

export default graphql(CURRENT_USER_QUERY, 
  skip: () => !localStorage.get("auth_token"),
)(Menu);

现在的问题是如何在本地存储发生变化时重新渲染这个组件。通常 react 不会监听本地存储来触发重新渲染,而是使用以下三种方法之一完成重新渲染:

    组件的状态发生变化 组件的父级重新渲染(通常为子级使用新的道具) 在组件上调用forceUpdate

(请注意,订阅上下文的更改也会触发重新渲染,但我们不想弄乱上下文;-))

您可能希望使用 2. 和 3. 或 1. 和 2. 的组合。 在您的情况下,更改路线就足够了(就像您在登录功能中所做的那样)。如果这不起作用,您可以在登录后使用 &lt;Login onLogin=() =&gt; this.forceUpdate() /&gt; 上的回调属性在 App 组件上调用 this.forceUpdate()

【讨论】:

skip 选项非常棒。在下面的示例中,我基本上提取了整个查询,以便我可以在组件生命周期方法中控制它。 除此之外,我不认为 forceUpdate 是 John 正在寻找的解决方案。 Redux 是。因为您并不想使用 forceUpdate - 尽管我在示例源代码中也使用了它,因为没有其他选项。 我觉得 Redux 在这里保存一个属性有点矫枉过正。我们有一个大的 Apollo 应用程序,我们根本不使用 Redux。相反,我们使用一些 React 状态来保存一些不在服务器状态中的东西(通常是 UI 状态)。您可以在 App 组件上创建一个“userIsLoggedIn”状态属性,而不是 Redux。然后问题是 forceUpdate 是否不是更优雅,因为您将没有两个真实的登录来源。 Redux 并没有真正统一这一点,因为您希望通过页面重新加载来保持登录状态。 是的,我在 GitHub 上花了很多时间来帮助这个人,甚至在我的一个旧示例中,我将 userIsLoggedIn 标志存储在 App 组件中。这样做的问题是您要么想要使用context,要么可能必须将userIsLoggedIn 标志传递给需要知道用户是否手动登录的每个组件。你可以通过使用 redux 来避免这种头痛。 Redux 基本上是一个花哨的状态管理器。不使用它可以为您节省一些kbs,因为您不再有一个依赖项,但是使用它可以使您的项目更具可扩展性。 Apollo 负责服务器端应用程序的状态。 Redux 之所以出现是因为客户端应用程序状态。这是两个不同的东西。【参考方案2】:

已编辑

1) 我刚刚创建了新链接https://codesandbox.io/s/0y3jl8znw

您想在componentWillReceiveProps 方法中获取用户数据:

  componentWillReceiveProps() 
    this.props.client.query(query: CURRENT_USER_QUERY)
    .then((response) => 
      this.setState( currentUser: response.data.currentUser)
    )
    .catch((e) => 
      console.log('there was an error ', e)
    )
  

这将使组件重新渲染。

2) 现在,当我们在组件的生命周期方法中移动查询调用时,我们可以完全控制它。如果您只想在本地存储中有内容时才调用查询,您只需将查询包装在一个简单的条件中:

  componentWillReceiveProps() 
    if(localstora.getItem('auth_token')) 
      this.props.client.query(query: CURRENT_USER_QUERY)
      .then((response) => 
        this.setState( currentUser: response.data.currentUser)
      )
      .catch((e) => 
        console.log('there was an error ', e)
      )
    
  

3) 您希望将全局应用程序状态存储在 redux 存储中。否则,您每次需要使用它时都必须获取用户信息。我建议在 App 组件中定义一个 state 并将所有全局值存储在那里。

【讨论】:

你认为没有App状态就没有办法工作吗?我不相信我不能使用阿波罗的力量! 另外我在网上看到很多人用 Apollo 2 关闭 Redux。但我不明白怎么做!这个问题是一个基本问题。不是吗? Redux 基本上是一个“全局”应用程序的状态。将用户信息保存在App 组件中是完全可以的。为什么每次需要处理用户信息时都要调用 API? :) 将不敏感的信息存储在组件中是非常好的。 我很想向您展示 redux 的强大功能,但我需要重新开始工作。 :D 对不起@Michal。为什么不使用阿波罗刚刚给我们的东西?它的缓存就像一个 Redux 的。除了我在后端没有的东西。他们只是在开发这个:github.com/apollographql/apollo-link-state 事实上。我现在想要的是只使用 Apollo 和 React(没有 apollo-link-state),我的问题是我需要在整个应用程序中重用 currentUser 信息,我讨厌本地组件状态。你的作品很好,只是不完整。但我们必须让它变得惊人!有什么想法吗?

以上是关于React、Apollo 2、GraphQL、身份验证。登录后如何重新渲染组件的主要内容,如果未能解决你的问题,请参考以下文章

graphql_devise 用于 Rails/Graphql/Apollo/React 中的身份验证。 “字段需要身份验证”错误

使用 apollo graphql 对 firebase 身份验证做出反应

反应 apollo graphql 和谷歌身份验证流程

Apollo graphql 连接的 React 组件没有重新渲染

React Apollo Link - 如何在使用 <Query /> 和 <Mutation /> 组件之外向 GraphQL 服务器查询身份验证令牌?

React 身份验证会话管理