在 QueryRenderer 中传递中继现代变量

Posted

技术标签:

【中文标题】在 QueryRenderer 中传递中继现代变量【英文标题】:Passing relay modern variable in QueryRenderer 【发布时间】:2017-10-14 07:56:13 【问题描述】:

我正在使用现代继电器。以下是给我一个错误,说 $limit 没有定义。我将如何定义 QueryRenderer 中的限制? 我的想法是限制是在 Main.js 中定义的,但看起来我需要以某种方式在 QueryRenderer 中引用它。我的 app.js 文件中有一个 QueryRenderer,它调用另一个组件 Main.js 上的片段。 app.js 长这样,Main.js 如下:

```js

import '../style/style.css'
import React from 'react'
import ReactDOM from 'react-dom'
import  QueryRenderer, graphql  from 'react-relay'
import environment from './createRelayEnvironment'
import Main from './components/Main'

// change rootContainer to QueryRenderer
ReactDOM.render(
  <QueryRenderer
    environment=environment
    query=graphql`
      query appQuery 
        store 
          ...Main_store
          
      
    `
    // variables=limit: 100, query: ''
    render=( error, props) => 
      if (props) 
        return <Main store=props.store />
       else 
        return <div>Loading</div>
      
    
  />,
  document.getElementById('react')
)

```

在此处调用的 ...Main_store 片段来自该组件 Main.js

```js

import React from 'react'
import 
  createFragmentContainer,
  createRefetchContainer,
  graphql
 from 'react-relay'
import  debounce  from 'lodash'

import Business from './Business'
import CreateBusinessMutation from '../mutations/CreateBusinessMutation'

class Main extends React.Component 
  constructor (props) 
    super(props)
// TODO props.relay.* APIs do not exist on compat containers
// TODO needs manual handling
    this._loadMore = debounce(this._loadMore, 300)
    this.props.relay.Variables =  limit: 100, query: '' 
  

  search = (e) => 
// TODO needs manual handling
    this._loadMore( query: e.target.value )
  ;

  setLimit = (e) => 
// TODO needs manual handling
    this._loadMore( limit: Number(e.target.value) )
  ;

  handleSubmit = (e) => 
    e.preventDefault()
    let onSuccess = () => 
      $('#modal').closeModal()
    

    let onFailure = (transaction) => 
      const error = transaction.getError() || new Error('Mutation failed.')
      console.error(error)
    

    let name = this.refs.newName.value = ''
    let url = this.refs.newUrl.value = ''

    CreateBusinessMutation.commit(
      this.props.relay.environment,
      name,
      url,
      this.props.store
    ),
    onFailure, onSuccess
  

  componentDidMount () 
    $('.modal-trigger').leanModal()
  

  render () 
    let content = this.props.store.businessConnection.edges.map(edge => 
      return <Business key=edge.node.id business=edge.node />
    )
    return (
      <div>
        <div className="input-field">
          <input id="search" type="text" onChange=this.search />
          <label htmlFor="search">Search All Businesses</label>
        </div>

        <div className="row">
          <a className="waves-effect waves-light btn modal-trigger right light-blue white-text" href="#modal">Add New Business</a>
        </div>

        <ul>
          content
        </ul>

        <div className="row">
          <div className="col m3 hide-on-small-only">
            <div className="input-field">
              <select id="showing" className="browser-default"
// TODO props.relay.* APIs do not exist on compat containers
                onChange=this.setLimit defaultValue=this.props.relay.variables.limit>
                <option value="100">Show 100</option>
                <option value="200">Show 200</option>
              </select>
            </div>
          </div>
        </div>

        <div id="modal" className="modal modal-fixed-footer">
          <form onSubmit=this.handleSubmit>
            <div className="modal-content">
              <h5>Add New Business</h5>
              <div className="input-field">
                <input type="text" id="newName" ref="newName" required className="validate" />
                <label htmlFor="newName">Name</label>
              </div>
              <div className="input-field">
                <input type="url" id="newUrl" ref="newUrl" required className="validate" />
                <label htmlFor="newUrl">Url</label>
              </div>
            </div>
            <div className="modal-footer">
              <button type="submit" className="waves-effect waves-green btn-flat green darken-3 white-text">
                <strong>Add</strong>
              </button>
              <a href="#!" className="modal-action modal-close waves-effect waves-red btn-flat">Cancel</a>
            </div>
          </form>
        </div>
      </div>
    )
  
  _loadMore () 
    // Increments the number of stories being rendered by 10.
    const refetchVariables = fragmentVariables => (
      query: fragmentVariables.query,
      limit: fragmentVariables.limit
    )
    this.props.relay.refetch(refetchVariables, null);
  


Main = createRefetchContainer(Main, 
  /* TODO manually deal with:
  initialVariables: 
    limit: 100,
    query: ''
  
  */
  store: graphql`
    fragment Main_store on Store 
      id,
      businessConnection(first: $limit, query: $query) 
        edges 
          node 
            id,
            ...Business_business
          
        
      
    
  `
,
  graphql`
    query MainRefetchQuery($limit: Int, $query: String) 
        store 
          ...Main_store
        
      
  `,
)

export default Main

```

这是查询中 Chrome DevTools 网络选项卡中的错误。


    "errors": [
        
            "message": "Variable \"$limit\" is not defined by operation \"appQuery\".",
            "locations": [
                
                    "line": 10,
                    "column": 29
                ,
                
                    "line": 1,
                    "column": 1
                
            ]
        ,
        
            "message": "Variable \"$query\" is not defined by operation \"appQuery\".",
            "locations": [
                
                    "line": 10,
                    "column": 44
                ,
                
                    "line": 1,
                    "column": 1
                
            ]
        ,
        
            "message": "Variable \"$showLikes\" is not defined by operation \"appQuery\".",
            "locations": [
                
                    "line": 24,
                    "column": 27
                ,
                
                    "line": 1,
                    "column": 1
                
            ]
        
    ]

任何想法都将不胜感激。(这主要是使用Relay Conversion Playbook 生成的)谢谢。

更新 - 添加模式以帮助获得答案:

```

类型业务实现节点 # 对象的ID 身份证:身份证! 名称:字符串 网址:字符串 状态:字符串 喜欢计数:整数 创建时间:字符串

# A connection to a list of items.
type BusinessConnection 
  # Information to aid in pagination.
  pageInfo: PageInfo!

  # A list of edges.
  edges: [BusinessEdge]


# An edge in a connection.
type BusinessEdge 
  # The item at the end of the edge
  node: Business

  # A cursor for use in pagination
  cursor: String!


input CreateBusinessInput 
  name: String!
  url: String!
  clientMutationId: String


type CreateBusinessPayload 
  businessEdge: BusinessEdge
  store: Store
  clientMutationId: String


type Mutation 
  createBusiness(input: CreateBusinessInput!): CreateBusinessPayload
  thumbsUp(input: ThumbsUpInput!): ThumbsUpPayload


# An object with an ID
interface Node 
  # The id of the object.
  id: ID!


# Information about pagination in a connection.
type PageInfo 
  # When paginating forwards, are there more items?
  hasNextPage: Boolean!

  # When paginating backwards, are there more items?
  hasPreviousPage: Boolean!

  # When paginating backwards, the cursor to continue.
  startCursor: String

  # When paginating forwards, the cursor to continue.
  endCursor: String


type Query 
  # Fetches an object given its ID
  node(
    # The ID of an object
    id: ID!
  ): Node
  store: Store


type Store implements Node 
  # The ID of an object
  id: ID!
  businessConnection(after: String, first: Int, before: String, last: Int, query: String): BusinessConnection


input ThumbsUpInput 
  businessId: String
  clientMutationId: String


type ThumbsUpPayload 
  business: Business
  clientMutationId: String

```

【问题讨论】:

【参考方案1】:

QueryRenderer 可以采用 variables 属性。试试这个:

<QueryRenderer
  // ...
  variables=
    limit: 10,
  
  // ...
/>

现在您可以在 QueryRenderer 查询的任何片段子项中引用 $limit

如果您需要更改$limit的值并重新获取,请使用createRefetchContainer并调用refetch方法。

This GitHub comment 解决了这个问题,并将被纳入 Relay Modern 文档中。

示例可用here

【讨论】:

“使用 createRefetchContainer”是什么意思?您的意思是创建一个附加组件并将其包装在 RefetchContainer 中吗?我不确定您将如何使用 RefetchContainer 来修改变量并调用 refetch 以重新执行根查询。 @bjlevine 我认为 Facebook 文档对此很好 - 有一个如何执行重新获取和更改查询变量的示例。然后,您的 refetchContainer 将在 QueryRenderer(或适当的子级)下呈现。 facebook.github.io/relay/docs/refetch-container.html

以上是关于在 QueryRenderer 中传递中继现代变量的主要内容,如果未能解决你的问题,请参考以下文章

将变量传递给现代中继中的片段容器

如何将自定义道具传递给 QueryRenderer 渲染函数?

GraphQL / Relay - 是不是需要在主 QueryRenderer 中查询所有表?

如何乐观响应中继现代突变中的连接属性?

在没有查看器的情况下中继现代分页

中继现代嵌套分页