Relay Modern RefetchContainer道具不会传递给组件

cnt*_*rlz 10 javascript graphql relayjs react-redux relaymodern

我在Relay Modern中设置refetchContainer时遇到了一些问题.父组件是QueryRenderer,它运行初始查询,适当地填充子组件的道具(a-prop-riately?eh?eh?!).refetchContainer指定我们所有的变量,并在输入字段的onChange事件上,使用新变量重新运行查询.这一切都很完美,除了孩子的道具永远不会更新收到的新数据.我可以向下钻取Relay存储,看到确实收到了带有适当数据的查询.我已经对这个问题感到震惊了一段时间,我会感激一些帮助.可能是我想念的简单事情.Lord知道Relay Modern文档很少.

我已经四处寻找,找不到合适的解决方案.这家伙似乎遇到了类似的问题: 继电器重新提取没有显示结果

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);
Run Code Online (Sandbox Code Playgroud)

具有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)
      }
    }
  `,
);
Run Code Online (Sandbox Code Playgroud)

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]
}
Run Code Online (Sandbox Code Playgroud)

网络调用正确,并按预期返回数据. NetworkCalls

似乎@arguments指令可以在这里放弃重新获取查询:

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

(删除它似乎没有效果)

我已经尝试将@arguments指令添加到父组件的片段中,按照此处的建议:将变量传递给relay modern中的片段容器,不起作用.

jst*_*ada 6

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

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

在这个特定的场景中,容器不重新渲染的原因,即为什么它不订阅由 触发的更改refetchQuery,是由于订阅是如何设置的。订阅基本上是对 a 的订阅snapshot,它基本上代表一个具体的片段以及在给定时间点与其关联的数据和记录——当与快照关联的记录发生更改时,该快照的订阅将收到更改通知.

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

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

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


his*_*_py 5

哦,我想我解决了类似的问题。如果我没记错的话,我相信“id”Relay 用于识别要传递道具的组件,包括初始查询的变量,因此请尝试从 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>;
  }}
/>
Run Code Online (Sandbox Code Playgroud)

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)
    }
  `
);
Run Code Online (Sandbox Code Playgroud)

请注意,上面的示例假设graphql.experimental不推荐使用Relay v1.3 。另外,我不记得使用这个@arguments技巧是否可以使您的searchUsers工作别名化。

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

最后,根据您的评论,我同意这可能是一个 BUG。让我们看看您报告的问题的进展情况。