如何让 QueryRenderer 传播 parent 道具更改?

How to get the QueryRenderer to propagate parent prop changes?

使用 Relay Modern v.1.4.1,考虑以下 List 组件。

它需要两个道具 foobar 并使用这些道具和 GraphQL 查询的结果渲染一个 Table 组件:

class List extends React.Component {

  constructor(props) {
    super(props);
    // I accept this.props.foo and this.props.bar
    this.renderQuery = this.renderQuery.bind(this);
  }

  render() {
    return <QueryRenderer
      environment={this.props.relayEnvironment}
      query={SomeQuery}
      variables={{
        count: 20,
      }}
      render={this.renderQuery}
    />;
  }

  renderQuery(readyState) {
    console.log("List component props:");
    console.log(this.props);
    return <Table 
      foo={this.props.foo} bar={this.props.bar} 
      data={readyState.data}
    />
  }

}

现在,对于 Table 组件的初始渲染,foobar 设置正确,但是如果 foobar 之后更改由于 QueryRenderer.

,新值不会传播到 Table 组件

因为 QueryRenderer 只有 re-renders 如果 variablesSomeQuery 更改 renderQuery 方法不会被触发,因为 QueryRenderer 会认为不需要它,因此 Table 组件保留旧的 prop 值。

由于将 props 传递给 children 是一项非常常见的任务,因此 QueryRenderer 没有注意到 parent 的 prop 变化这一事实造成了很大的问题。我一直想知道这可能是什么解决方案,并提出了一些选择:

  1. 使用Context 绕过此行为。但是,通常不鼓励使用 Context ,除非你有充分的理由 + 感觉像是一个肮脏的 hack 来规避这个问题。
  2. 强制 QueryRenderer 到 re-render 与之前相同的 readyState。这也许可以使用 refs 来实现,但您需要自己检查何时 re-render。
  3. 不知何故让 QueryRenderer 关心我的道具。这显然是正确的方法,但我没有在文档中找到任何允许这样做的内容,因此我需要做一些事情,比如从 QueryRenderer 或其实现此行为的子类创建高阶组件。

理想情况下,我希望有一种本机方式来让 QueryRenderer 查看道具更改,例如

<QueryRenderer
  environment={this.props.relayEnvironment}
  query={SomeQuery}
  variables={{
    count: 20,
  }}
  render={this.renderQuery}
  propagateProps={this.props}
/>

<QueryRenderer
  environment={this.props.relayEnvironment}
  query={SomeQuery}
  variables={{
    count: 20,
  }}
  render={this.renderQuery}
  {...this.props}
/>

有什么想法吗?

删除您的 Class 组件并将上面的代码更改为:

const List = (parentProps) => (
  <QueryRenderer
    environment={parentProps.relayEnvironment}
    query={SomeQuery}
    variables={{
      count: 20,
    }}
    render={({ props }) => (
      <Table 
        foo={this.parentProps.foo} bar={this.parentProps.bar} 
        data={props.data}
      />
    )}
  />
)

QueryRenderer 本身已经是一个 React 组件,您通常不必将其包装在 class 组件渲染中。

List 现在是一个纯函数组件,当它接收到新的 props (parentProps) 时,它会重新渲染,因此 Table 会重新渲染