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) 这是正确的方法吗?
【问题讨论】:
<Route component=Menu />
这行代码我好像没找到??
被评论是因为我试图不使用它。
@Dane,如果我删除该行并仅使用 <Menu />
它根本不会重新渲染。
我重置了有问题的代码。
关于(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. 的组合。
在您的情况下,更改路线就足够了(就像您在登录功能中所做的那样)。如果这不起作用,您可以在登录后使用 <Login onLogin=() => this.forceUpdate() />
上的回调属性在 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 连接的 React 组件没有重新渲染
React Apollo Link - 如何在使用 <Query /> 和 <Mutation /> 组件之外向 GraphQL 服务器查询身份验证令牌?