如何让 QueryRenderer 传播 parent 道具更改?
How to get the QueryRenderer to propagate parent prop changes?
使用 Relay Modern v.1.4.1,考虑以下 List
组件。
它需要两个道具 foo
和 bar
并使用这些道具和 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
组件的初始渲染,foo
和 bar
设置正确,但是如果 foo
或 bar
之后更改由于 QueryRenderer
.
,新值不会传播到 Table
组件
因为 QueryRenderer
只有 re-renders 如果 variables
为 SomeQuery
更改 renderQuery
方法不会被触发,因为 QueryRenderer
会认为不需要它,因此 Table
组件保留旧的 prop 值。
由于将 props 传递给 children 是一项非常常见的任务,因此 QueryRenderer
没有注意到 parent 的 prop 变化这一事实造成了很大的问题。我一直想知道这可能是什么解决方案,并提出了一些选择:
- 使用Context 绕过此行为。但是,通常不鼓励使用 Context ,除非你有充分的理由 + 感觉像是一个肮脏的 hack 来规避这个问题。
- 强制
QueryRenderer
到 re-render 与之前相同的 readyState
。这也许可以使用 refs
来实现,但您需要自己检查何时 re-render。
- 不知何故让
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 会重新渲染
使用 Relay Modern v.1.4.1,考虑以下 List
组件。
它需要两个道具 foo
和 bar
并使用这些道具和 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
组件的初始渲染,foo
和 bar
设置正确,但是如果 foo
或 bar
之后更改由于 QueryRenderer
.
Table
组件
因为 QueryRenderer
只有 re-renders 如果 variables
为 SomeQuery
更改 renderQuery
方法不会被触发,因为 QueryRenderer
会认为不需要它,因此 Table
组件保留旧的 prop 值。
由于将 props 传递给 children 是一项非常常见的任务,因此 QueryRenderer
没有注意到 parent 的 prop 变化这一事实造成了很大的问题。我一直想知道这可能是什么解决方案,并提出了一些选择:
- 使用Context 绕过此行为。但是,通常不鼓励使用 Context ,除非你有充分的理由 + 感觉像是一个肮脏的 hack 来规避这个问题。
- 强制
QueryRenderer
到 re-render 与之前相同的readyState
。这也许可以使用refs
来实现,但您需要自己检查何时 re-render。 - 不知何故让
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 会重新渲染