每次在 react-apollo 和 graphql 中调用组件时如何向服务器重新发送查询

How to resend queries to server every time a component is called in react-apollo and graphql

我有这个项目,有点像 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,但该组件未显示正确的详细信息。只有当我重新加载页面时,我才能获得正确的详细信息。进行一些调试后,我意识到当我第二次点击 wards 中的任何这些用户名时,甚至都没有对服务器进行查询。只有当我重新加载页面时,才会进行查询。我需要帮助才能知道 每次在 react-apollo 和 graphql 中调用组件时如何向服务器重新发送查询。 (我是 graphql 的初学者)

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