【问题标题】:Is there a way to pass a dynamic GraphQL query to a graphql() decorated Component when using Apollo Client 2.0?使用 Apollo Client 2.0 时,有没有办法将动态 GraphQL 查询传递给 graphql() 修饰的组件?
【发布时间】:2018-02-26 10:19:01
【问题描述】:

我在处理动态数据时有时会遇到这个问题。这是在需要的数据可用之前安装的高阶组件的问题。

我希望在 Apollo 客户端中使用 graphql() HOC 装饰一个组件,如下所示:

export default compose(
  connect(),
  graphql(QUERY_NAME),  <-- I want QUERY_NAME to be determined at run-time
)(List)

问题是我不知道如何让 Apollo 使用由包装组件在运行时确定的查询

我有一个基于类型导出查询的文件:

import listFoo from './foo'
import listBar from './bar'
import listBaz from './baz'

export default {
  foo,
  bar,
  baz,
}

我可以通过listQueries[type] 访问它们,但type 只在组件内部知道,它可以作为this.props.fromRouter.type 使用。

有没有我可以用来实现的策略:

export default compose(
  connect(),
  graphql(listQueries[type]),
)(List)

我认为可能有办法做到这一点:

export default compose(
  connect(),
  graphql((props) => ({
    query: listQueries[props.fromRouter.type],
  })),
)(List)

我走对了吗?

另一种可能的解决方案是让组件生成自己的子组件,该子组件用graphql() 包装,因为那时会知道查询。

例如:

const tableWithQuery = graphql(listQueries[props.fromRouter.type])((props) => {
  return <Table list={props.data} />
})

【问题讨论】:

    标签: reactjs apollo react-apollo


    【解决方案1】:

    我想我明白了。

    1. 我有一个路由器组件,它读取this.props.match.params 以获取视图的类型并请求操作

    2. 有了这些信息,我可以只创建一个列表、创建、编辑和查看组件,并为每个组件提供所需的任何查询。

    3. 我创建了一个函数,用于获取提供的 type 的所有查询和突变。

    4. 实际上非常简单,只需将&lt;List /&gt; 之类的组件用graphql() 包装起来,然后为其提供刚刚确定的正确查询或突变。

    5. 现在,组件安装时 this.props.data 填充了正确的数据

    6. 我分散了所有查询和突变,以防万一我需要它们。我怀疑当我去阅读this.props.data[listQueryName] 时我会需要它们。 (它将抓取数据,例如,this.props.data.getAllPeople

    这是逻辑(我将包括所有这些,以尽量减少未来搜索者的混淆):

    import React, { Component } from 'react'
    import PropTypes from 'prop-types'
    import { connect } from 'react-redux'
    import { compose, graphql, withApollo } from 'react-apollo'
    import listQueries from './list/queries'
    import createMutations from './forms/create/mutations'
    import editMutations from './forms/edit/mutations'
    import viewQueries from './forms/view/queries'
    import List from './list/List'
    import Create from './forms/create/Create'
    import Edit from './forms/edit/Edit'
    import View from './forms/view/View'
    // import Delete from './delete/Delete'
    
    class Router extends Component {
      constructor(props) {
        super(props)
        this.state = {
          serverErrors: [],
        }
      }
    
      getGraphQL = (type) => {
        console.log('LIST QUERY', listQueries[type])
        console.log('LIST QUERY NAME', listQueries[type].definitions[0].name.value)
        console.log('CREATE MUTATION', createMutations[type])
        console.log('CREATE MUTATION NAME', createMutations[type].definitions[0].name.value)
        console.log('EDIT MUTATION', editMutations[type])
        console.log('EDIT MUTATION NAME', editMutations[type].definitions[0].name.value)
        console.log('VIEW QUERY', viewQueries[type])
        console.log('VIEW QUERY NAME', viewQueries[type].definitions[0].name.value)
        return {
          listQuery: listQueries[type],
          listQueryName: listQueries[type].definitions[0].name.value,
          createMutation: createMutations[type],
          createMutationName: createMutations[type].definitions[0].name.value,
          editMutation: editMutations[type],
          editMutationName: editMutations[type].definitions[0].name.value,
          viewQuery: viewQueries[type],
          viewQueryName: viewQueries[type].definitions[0].name.value,
        }
      }
    
      renderComponentForAction = (params) => {
        const { type, action } = params
        const GQL = this.getGraphQL(type)
        const {
          listQuery, createMutation, editMutation, viewQuery,
        } = GQL
    
        // ADD QUERIES BASED ON URL
        const ListWithGraphQL = graphql(listQuery)(List)
        const CreateWithGraphQL = graphql(createMutation)(Create)
        const EditWithGraphQL = compose(
          graphql(viewQuery),
          graphql(editMutation),
        )(Edit)
        const ViewWithGraphQL = graphql(viewQuery)(View)
        if (!action) {
          console.log('DEBUG: No action in URL, defaulting to ListView.')
          return <ListWithGraphQL fromRouter={params} {...GQL} />
        }
        const componentFor = {
          list: <ListWithGraphQL fromRouter={params} {...GQL} />,
          create: <CreateWithGraphQL fromRouter={params} {...GQL} />,
          edit: <EditWithGraphQL fromRouter={params} {...GQL} />,
          view: <ViewWithGraphQL fromRouter={params} {...GQL} />,
          // delete: <Delete fromRouter={params} {...GQL} />,
        }
        if (!componentFor[action]) {
          console.log('DEBUG: No component found, defaulting to ListView.')
          return <ListWithGraphQL fromRouter={params} {...GQL} />
        }
        return componentFor[action]
      }
      render() {
        return this.renderComponentForAction(this.props.match.params)
      }
    }
    
    Router.propTypes = {
      match: PropTypes.shape({
        params: PropTypes.shape({ type: PropTypes.string }),
      }).isRequired,
    }
    
    export default compose(connect())(withApollo(Router))
    

    如果此代码以后对某人有用。我建议将所有内容都注释掉,除了呈现列表视图所需的代码。首先验证道具是否进入了一个小小的“hello world”视图。然后,一旦您在那里获得正确的数据,您将完成最困难的部分。

    【讨论】:

    • 您在这里的渲染方法中创建了很多昂贵的对象,我不确定这是一个理想的方法。我认为你在正确的轨道上建议 graphql() 可以将一个函数作为从 props 派生查询的第一个参数,但遗憾的是我认为该库还不支持。
    猜你喜欢
    • 2019-04-02
    • 2017-07-21
    • 2018-01-27
    • 2019-03-13
    • 2018-02-10
    • 2017-04-22
    • 2018-03-10
    • 2020-04-04
    • 2018-04-17
    相关资源
    最近更新 更多