【问题标题】:Relay Modern RefetchContainer props aren't passed to componentRelay Modern RefetchContainer 道具未传递给组件
【发布时间】:2017-12-27 23:27:18
【问题描述】:

我在 Relay Modern 中设置 refetchContainer 时遇到了一些问题。父组件是 QueryRenderer,它运行初始查询,适当地填充子组件的 props (a-prop-riately?eh?eh?!)。 refetchContainer 指定了我们所有的变量,并且在输入字段的 onChange 事件中,使用新变量重新运行查询。这一切都很完美,除了孩子的道具永远不会随着收到的新数据而更新。我可以深入了解 Relay 存储,并查看确实收到了带有适当数据的查询。一段时间以来一直在努力解决这个问题,我将不胜感激。可能我缺少一些简单的东西。上帝知道 Relay Modern 的文档很少。

我四处寻找,找不到合适的解决方案。这家伙似乎有类似的问题: relay refetch doesn't show the result

带有QueryRenderer的父组件:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { graphql, QueryRenderer } from 'react-relay';
import Search from './Search';

const propTypes = {
  auth: PropTypes.object.isRequired,
};

class SearchContainer extends Component {
  render() {
    return (
      <QueryRenderer
        query={graphql`
          query SearchContainerQuery($search: String!){
            users: searchUsers(search:$search, first:10){
              ...Search_users
            }
          }`}
        variables={{ search: 'someDefaultSearch' }}
        environment={this.props.auth.environment}
        render={({ error, props }) => {
          if (error) {
            console.log(error);
          }
          if (props) {
            return <Search users={props.users} />;
          }
          return <div>No Dice</div>;
        }}
      />
    );
  }
}

SearchContainer.propTypes = propTypes;

export default connect(state => ({ auth: state.auth }))(SearchContainer);

带有createRefetchContainer的子组件:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { createRefetchContainer, graphql } from 'react-relay';

const propTypes = {
  relay: PropTypes.object.isRequired,
  users: PropTypes.object,
};

const defaultProps = {
  users: {},
};

class Search extends Component {
  render() {
    return (
      <div>
        <input
          type="text"
          onChange={(e) => {
            e.preventDefault();
            this.props.relay.refetch({
              search: e.target.value,
            });
          }}
        />
        <ul>
          {this.props.users.nodes.map(user =>
            <li key={user.id}>{user.username}</li>,
          )}
        </ul>
      </div>
    );
  }
}

Search.propTypes = propTypes;
Search.defaultProps = defaultProps;

export default createRefetchContainer(
  Search,
  {
    users: graphql.experimental`
      fragment Search_users on SearchUsersConnection
      @argumentDefinitions(
        search: {type: "String", defaultValue: ""}
      ) {
        nodes {
            id
            displayName
            username
          }
      }
    `,
  },
  graphql.experimental`
    query SearchRefetchQuery($search: String!) {
      users: searchUsers(search:$search, first:10){
        ...Search_users @arguments(search: $search)
      }
    }
  `,
);

GraphQL 看起来像这样:

# A connection to a list of `User` values.
type SearchUsersConnection {
  # Information to aid in pagination.
  pageInfo: PageInfo!

  # The count of *all* `User` you could get from the connection.
  totalCount: Int

  # A list of edges which contains the `User` and cursor to aid in pagination.
  edges: [SearchUsersEdge]

  # A list of `User` objects.
  nodes: [User]
}

适当地进行网络调用,并按预期返回数据。 NetworkCalls

似乎@arguments 指令可以被排除在refetch 查询之外:

query SearchRefetchQuery($search: String!) {
      users: searchUsers(search:$search, first:10){
          ...Search_users @arguments(search: $search)
      }
}

(去掉好像没有效果)

我已尝试按照此处的建议将@arguments 指令添加到父组件的片段中:Pass variables to fragment container in relay modern,但没有效果。

【问题讨论】:

  • 很抱歉帮不上什么忙.. fwiw 我已经完全放弃了 refetchContainers,只是为了简单地将新道具传递给完成工作的 QueryRenderer。例如:github.com/NCI-GDC/portal-ui/blob/next/src/packages/@ncigdc/…
  • @azium 是的,这似乎工作得很好。只是让我感到困扰的是,专门为此设计的 refetchContainer 设置起来非常棘手!
  • 我遇到了完全相同的问题,而且我的头也撞到墙上了 :(
  • 我有一个几乎相同的查询工作正常,在您的代码中找不到任何明显的错误。您是否尝试升级到更新的版本? ...或者只是也许,尝试从 redux 中解开它,看看它是否可以自己工作...
  • 哦,我想我也遇到了类似的问题。如果我没记错的话,我相信用于识别组件的“id”中继包含初始查询的变量,因此请尝试通过将 searchUsers(..) 移动到片段然后在查询中来解开 QueryRenderer 中的容器片段只是...Search_user。您必须将 Search_user 定义为根的片段,即:在我的情况下,它类似于 fragment Search_user on RootQueryType。我的最后一个建议是打开你的调试器,看看当你得到数据时发生了什么。

标签: javascript react-redux graphql relayjs relaymodern


【解决方案1】:

哦,我想我遇到了类似的问题。如果我没记错的话,我相信“id”中继用于识别要传递道具的组件,其中包括初始查询的变量,因此请尝试从 QueryRenderer 的查询中解开容器片段。

对我有用的设置如下:

<QueryRenderer
  variables={{search: 'someDefaultSearch', count: 10}}
  query={graphql`
    query SearchContainerQuery($search: String!, $count: Int!){
      # if we want defaults we need to "prepare" them from here
      ...Search_users @arguments(search: $search, count: $count)
    }
  `}
  environment={this.props.auth.environment}
  render={({ error, props: relayProps }) => {
    // I use relayProps to avoid possible naming conflicts
    if (error) {
      console.log(error);
    }
    if (relayProps) {
      // the users props is "masked" from the root that's why we pass it as is
      return <Search users={relayProps} />;
    }
    return <div>No Dice</div>;
  }}
/>

refetchContainer 看起来像这样:

export default createRefetchContainer(
  Search,
  {
    users: graphql`
      # In my schema the root is called RootQueryType 
      fragment Search_users on RootQueryType
      @argumentDefinitions(
        search: {type: "String"}
        count: {type: "Int!"}
      ) {
        searchUsers(search: $search, first: $count) {
          nodes {
            id
            displayName
            username
          }
        }
      }
    `
  },
  graphql`
    query SearchRefetchQuery($search: String!, $count: Int!) {
      ...Search_users @arguments(search: $search, count: $count)
    }
  `
);

请注意,以上示例假定 Relay v1.3 已弃用 graphql.experimental。另外,我不记得使用@arguments 技巧是否可以使您的别名searchUsers 工作。

我的最后一个建议是打开你的调试器,看看当你得到数据时发生了什么。

最后,根据您的 cmets,我同意这可能是一个 BUG。让我们看看您报告的问题是如何演变的。

【讨论】:

    【解决方案2】:

    正如其他答案中提到的,这实际上是预期的行为,我将尝试稍微扩展答案。

    当调用 refetch 并执行 refetchQuery 时,Relay 实际上并没有使用查询结果来重新渲染组件。它所做的只是将有效负载标准化到存储中并触发任何相关订阅。这意味着如果获取的数据与挂载的容器订阅的数据无关(例如,使用完全不同的节点 id,没有任何数据重叠),那么组件将不会重新渲染。

    在这种特定情况下,容器不重新渲染的原因,即它不订阅refetchQuery 触发的更改的原因是由于订阅的设置方式。订阅基本上是对snapshot 的订阅,它基本上代表一个具体片段以及在给定时间点与之关联的数据和记录——当与快照关联的记录发生更改时,该快照的订阅将是通知更改。

    在这种情况下,鉴于容器的片段没有变量,它将订阅的快照将仅与初始节点相关联;在 refetch 发生并更新 store 后,新节点的记录将被更新,但与原始快照关联的记录没有更改,因此订阅它的容器不会收到通知。

    这意味着 Refetch 容器仅在您更改组件片段中的变量时才真正使用。此处提供的解决方案是有效的,即在片段中包含用于重新获取容器的变量或在 QueryRenderer 中设置新变量一级。

    这肯定可以在文档中更清楚地说明,所以我会更新它们以反映这一点。我希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 2017-11-09
      • 2018-05-13
      • 2019-08-06
      • 2018-03-27
      • 1970-01-01
      • 2018-01-03
      • 2020-09-01
      • 2019-02-17
      • 2018-06-27
      相关资源
      最近更新 更多