【问题标题】:How to resend queries to server every time a component is called in react-apollo and graphql每次在 react-apollo 和 graphql 中调用组件时如何将查询重新发送到服务器
【发布时间】:2018-10-14 09:22:07
【问题描述】:

我有这个项目,有点像 Facebook。这个想法是,当用户在他们的个人资料页面中时,他们应该看到他们朋友的用户名列表。单击每个用户名后,应用程序会从 url 中获取该人的 id,然后向服务器发送一个 graphql 查询,以获取该人的所有相关详细信息。 下面是当用户点击任何朋友的用户名时调用的方法。这按预期工作:

onClickFriend(e) {
    e.preventDefault()
    this.props.history.push(`/friends/${ e.target.id}`)
}

然后在处理用户访问的url的组件(即显示好友资料的组件)中包含如下代码:

import React from 'react'
import PostsColumn from "./posts/PostsColumn"
import NewPostForm from "./posts/NewPostForm"
import {fetchFriendProfile} from "../queries/queries"
import {graphql} from 'react-apollo'
import {withRouter } from 'react-router'

const FriendProfile=({data})=>{
    const {loading, error, fetchFriendProfile} = data
    if (loading) return <p>Loading...</p>
    if (error) return <p>{error}(</p>

    const {username, birthday, profile_picture} = fetchFriendProfile
    return (
        <div className="row">
            <div className="col-sm-3">
                <br/>

                <img src={`/uploads/${profile_picture}`} alt="Profile picture" width="200" height="200"/>
                <ul>
                    <li>{username}</li>
                    <li>{new Date(birthday).toDateString()}</li>
                </ul>
            </div>
            <div className="col-sm-6">
                <br/>
                <br/>
                <div className="content-feed">
                    <NewPostForm/>
                </div>

                {/*<PostsColumn />*/}
            </div>


        </div>
    )
}
export default graphql(fetchFriendProfile)(withRouter(FriendProfile))

而graphql查询是:

import {gql} from 'apollo-boost'
const fetchPalPosts = gql`
  {
 fetchFriendPosts(id:"${window.location.pathname.split('/')[2]}") {
    username
    birthday
    profile_picture
    }
    }
    `
export { fetchFriendProfile}

当网站加载时,我会看到我所有朋友的用户名列表,第一次点击任何用户,我都会得到所有相关的详细信息。但是,当我返回并单击另一个用户时,此配置文件组件会为我提供我单击的第一个用户的配置文件详细信息。 url 正在更改以反映这个新点击人员的 id,但该组件未显示正确的详细信息。只有当我重新加载页面时,我才能获得正确的详细信息。进行一些调试后,我意识到从第二次开始单击这些用户名中的任何一个时,甚至都没有对服务器进行查询。只有当我重新加载页面时才会进行查询。我需要帮助才能知道 每次在 react-apollo 和 graphql 中调用组件时如何向服务器重新发送查询。 (我是graphql的初学者)

【问题讨论】:

    标签: javascript reactjs graphql react-apollo


    【解决方案1】:

    除了查询之外,graphql HOC 还接受一个配置对象作为其第二个参数,允许您微调查询的行为方式。例如,您可以定义fetchPolicy,它决定了 Apollo 如何使用缓存。默认情况下,当获取相同的查询时,Apollo 会第一次访问服务器,然后使用缓存进行后续调用(这称为cache-first)。如果您希望组件在挂载时始终命中请求,可以将 fetch 策略设置为 network-only

    export default graphql(fetchFriendProfile, {
      options: (props) => ({
        fetchPolicy: 'network-only',
      }),
    })(withRouter(FriendProfile))
    

    您可以阅读有关获取政策的更多信息here

    也就是说,您无需更改获取策略即可实现所需的行为。部分问题在于您有效地对id 输入进行了硬编码——相反,您应该将任何动态输入作为变量传递给每个查询。这意味着您的查询需要如下所示:

    # Note: the actual type for $id will have to match your schema!
    query WhateverNameYouLike ($id: ID!){ 
      fetchFriendPosts(id: $id) {
        username
        birthday
        profile_picture
      }
    }
    

    然后你可以像这样传入你的变量:

    export default graphql(fetchFriendProfile, {
      options: (props) => ({
        variables: {
          id: window.location.pathname.split('/')[2],
        },
      }),
    })(withRouter(FriendProfile))
    

    旁注:您似乎也在使用 React Router,因此您应该能够从 match.params 获取 id,而不是自己解析位置。阅读更多here

    最后,重要的是要意识到 Apollo 会规范化它缓存的数据——它依赖于数据的 id(或 _id)属性来做到这一点。因此,如果您希望 cache-first 行为按预期工作,您需要 a) 确保您始终在查询中请求 id 字段,或者 b) 告诉 Apollo 使用不同的字段作为 id 通过相应地配置InMemoryCache。听起来您已经有一个 id 字段,因此修改查询以包含它很简单:

    query WhateverNameYouLike ($id: ID!){ 
      fetchFriendPosts(id: $id) {
        id
        username
        birthday
        profile_picture
      }
    }
    

    您可以阅读更多关于缓存规范化以及如何使用dataIdFromObject 来自定义 InMemoryCache 的默认行为here

    【讨论】:

      猜你喜欢
      • 2019-05-23
      • 2018-08-17
      • 2018-08-07
      • 2017-03-25
      • 2018-03-17
      • 2020-03-14
      • 2020-01-18
      • 2017-12-02
      • 2018-07-09
      相关资源
      最近更新 更多