如何将数据连线到react-router-relay的深层组件? [英] How to wire data to a deep component in react-router-relay?
问题描述
我有这样的路线
< Route path =/ searchcomponent = {Search}>
基本的 Search
组件看起来像这样
class Search React.Component {
constructor(props){
super(props)
this.state = {query:''}
}
handleSubmit(event){
event.preventDefault()
this.setState({query:this.refs.queryInput ()。
返回< EmptySearchResult />
else
return< SearchResult query = {this.state.query} />
}
render(){
return(
< div className =searchContainer>
< div className =row>
< div className =search>
< form onSubmit = {event => this.handleSubmit(event)}>
< input className =searchInputplaceholder =robocop ref =queryInput/>
< / form>
< / div>
< / div>
< div className =row>
{this.renderSearchResult()}
< / div>
< / div>
)
}
}
SearchResult
接力容器看起来像这样
class SearchResult extends React.Component {
render(){
var {viewer:{moviesByTitle:movies}} = this.props;
return(
< div className =searchResult>
{movies.edges.map((edge,i)=>
< div key = {i } className =rowItem scrollRowItem>
< Movie movie = {edge.node} />
< / div>)}
< / div>
)
}
}
导出默认值Relay.createContainer(SearchResult,{
initialVariables:{
query:'???'
},
fragments:{
viewer:()=> Relay.QL`
片段用户{
moviesByTitle(title:$ query,first:10){
edges {
node {
$ {Movie.getFragment('movie')}
}
}
}
}
`
$ p $ > 错误: 警告:RelayContainer:期望prop`viewer`提供给`SearchResult` ,但得到了'undefined`。如果这是故意的,则传递一个明确的`null`。
我在搜索组件中想要做的事情(以粗体显示)
const ViewerQueries = {
viewer:()=> Relay.QL`query {viewer}`
}
...
renderSearchResult(){
if(this.state.query ==='')
return< EmptySearchResult />
else
return< SearchResult query = {this.state.query} queries = {ViewerQueries} />
}
但是这当然不起作用,因为查询需要以某种方式附加到 Route
问题
$ b
-
我的搜索
组件仅仅是一个表示组件,不需要自己的数据。相反,它仅向 SearchResult
中继容器提供查询
prop。我应该如何构造组件和中继容器以正确地将它们附加到路径?
如何使用 SearchResult $> c $ c $> c code> query
prop在中继查询片段中设置变量?
-
从总体上理解观众抽象 - 我见过的大多数例子都是非常人为的,并没有表明他们如何在更现实的环境中工作;例如对不同资源有不同访问权限的用户,或者用于查看不同数据片段的程序的不同部分。
解决方案使用Relay的现代API,由 SearchResult
组件编写 refetchContainer
需要一个选项,用于执行具有不同变量的新查询,并在请求返回时呈现该查询的响应。
从'react'导入React,{Component};
进口从反弹中反弹;
从'react-relay'导入{graphql,createRefetchContainer};
$ b class class SearchResult extends React.Component {
componentWillReceiveProps(nextProps){
if(this.props.query!= nextProps.query){
debounce(() => this._searchMovies(),600);
}
}
_searchMovies(){
const refetchVariables = fragmentVariables => ({
query:this.props.query
});
this.props.relay.refetch(refetchVariables,null);
render(){
var {viewer:{moviesByTitle:movies}} = this.props;
return(
< div className =searchResult>
{movies.edges.map((edge,i)=>
< div key = {i } className =rowItem scrollRowItem>
< Movie movie = {edge.node} />
< / div>)}
< / div>
)
}
}
//与Relay Classic
类似的查询语法//只有语法上的区别是没有Movie.getFragment
module.exports = createRefetchContainer(SearchResult,{
viewer:graphql`
SearchResult_viewer on SearchResult {
@argumentDefinitions(
query:{type:String,defaultValue: }
){
moviesByTitle(title:$ query,first:10){
edges {
node {
... Movie_movie
}
}
}
}`
},
graphql`
query MoviesRefetchQuery($ query:String){
viewe r {
... SearchResult_viewer @arguments(query:$ query)
}
}
`);
I have a route like this
<Route path="/search" component={Search}>
The basic Search
component looks likes this
class Search extends React.Component {
constructor (props) {
super(props)
this.state = {query: ''}
}
handleSubmit (event) {
event.preventDefault()
this.setState({query: this.refs.queryInput.value})
}
renderSearchResult() {
if (this.state.query === '')
return <EmptySearchResult />
else
return <SearchResult query={this.state.query}/>
}
render() {
return (
<div className="searchContainer">
<div className="row">
<div className="search">
<form onSubmit={event => this.handleSubmit(event)}>
<input className="searchInput" placeholder="robocop" ref="queryInput" />
</form>
</div>
</div>
<div className="row">
{this.renderSearchResult()}
</div>
</div>
)
}
}
SearchResult
relay container looks like this
class SearchResult extends React.Component {
render() {
var {viewer: {moviesByTitle: movies}} = this.props;
return (
<div className="searchResult">
{movies.edges.map((edge,i) =>
<div key={i} className="rowItem scrollRowItem">
<Movie movie={edge.node} />
</div>)}
</div>
)
}
}
export default Relay.createContainer(SearchResult, {
initialVariables: {
query: '???'
},
fragments: {
viewer: () => Relay.QL`
fragment on User {
moviesByTitle(title: $query, first: 10) {
edges {
node {
${Movie.getFragment('movie')}
}
}
}
}
`
}
})
Error:
Warning: RelayContainer: Expected prop `viewer` to be supplied to `SearchResult`, but got `undefined`. Pass an explicit `null` if this is intentional.
What I was trying to do inside my Search component (changes in bold)
const ViewerQueries = {
viewer: () => Relay.QL`query { viewer }`
}
...
renderSearchResult() {
if (this.state.query === '')
return <EmptySearchResult />
else
return <SearchResult query={this.state.query} queries={ViewerQueries} />
}
But of course that doesn't work because the queries need to somehow be attached to the Route
Questions
My Search
Component is just a presentational component that does not need data of its own. Instead, it just feeds a query
prop to the SearchResult
relay container. How should I structure the Components and Relay containers to attach them to the Route properly?
How can I use the SearchResult
query
prop to set a variable in the relay query fragment?
I don't understand the "viewer" abstraction in general – most examples I've seen are very contrived and don't show how they'd work in a more realistic setting; eg users with different access to different resources, or different parts of your program that are intended to view different slices of data
解决方案 Using Relay's modern API, compose a refetchContainer
from SearchResult
component because of the need "an option to execute a new query with different variables and render the response of that query instead when the request comes back".
import React, { Component } from 'react';
import debounce from 'debounce';
import { graphql, createRefetchContainer } from 'react-relay';
class SearchResult extends React.Component {
componentWillReceiveProps(nextProps) {
if (this.props.query != nextProps.query) {
debounce(() => this._searchMovies(), 600);
}
}
_searchMovies() {
const refetchVariables = fragmentVariables => ({
query: this.props.query
});
this.props.relay.refetch(refetchVariables, null);
}
render() {
var { viewer: { moviesByTitle: movies } } = this.props;
return (
<div className="searchResult">
{movies.edges.map((edge, i) =>
<div key={i} className="rowItem scrollRowItem">
<Movie movie={edge.node} />
</div>)}
</div>
)
}
}
// Similar query syntax as Relay Classic
// Only syntactic difference is with absence of Movie.getFragment
module.exports = createRefetchContainer(SearchResult, {
viewer: graphql`
fragment SearchResult_viewer on SearchResult {
@argumentDefinitions(
query: {type: "String", defaultValue: ""}
) {
moviesByTitle(title: $query, first: 10) {
edges {
node {
...Movie_movie
}
}
}
}`
},
graphql`
query MoviesRefetchQuery($query: String) {
viewer {
...SearchResult_viewer @arguments(query: $query)
}
}
`);
这篇关于如何将数据连线到react-router-relay的深层组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!