如何将数据连线到react-router-relay的深层组件? [英] How to wire data to a deep component in react-router-relay?

查看:159
本文介绍了如何将数据连线到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


  1. 我的搜索组件仅仅是一个表示组件,不需要自己的数据。相反,它仅向 SearchResult 中继容器提供查询 prop。我应该如何构造组件和中继容器以正确地将它们附加到路径?

  2. 如何使用 SearchResult c $ c $> c code> query prop在中继查询片段中设置变量?
  3. 从总体上理解观众抽象 - 我见过的大多数例子都是非常人为的,并没有表明他们如何在更现实的环境中工作;例如对不同资源有不同访问权限的用户,或者用于查看不同数据片段的程序的不同部分。

    解决方案

    使用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

    1. 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?

    2. How can I use the SearchResult query prop to set a variable in the relay query fragment?

    3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆