在 React 中使用 Apollo.js 将查询映射到道具

Posted

技术标签:

【中文标题】在 React 中使用 Apollo.js 将查询映射到道具【英文标题】:Map query to props with Apollo.js in React 【发布时间】:2017-12-22 15:06:13 【问题描述】:

我刚刚在我的服务器上设置了 graphql,并希望将 Apollo 连接到我的前端。

我能够将 Apollo 与 Redux (How to pass initial state to reducer) 集成,但现在想通过 redux connect 将状态映射到 props。

我当前的 Home 组件如下所示:

import React,  Component  from 'react'
import  connect  from 'react-redux'
import  graphql  from 'react-apollo';

import './Home.css'

class Home extends Component 

  render() 
    return (
      <section className='home-container'>
        <h1>Site Name</h1>
      </section>
    )
  


const mapStateToProps = state => (
    curPage: state.curPage
)

export default connect(
  mapStateToProps,
)(Home)

我基本上想用mapQueryToProps 替换mapStateToProps,但是我不确定它是如何工作的。

这是否向我的/graphql 端点发出请求并将响应映射到curPage

这会在第一次渲染之前发生吗?就像this.props.curPage 可以在componentWillMount() 中使用一样吗? (出于 seo 的目的,我需要这个以确保所有内容都呈现在服务器端)。

在哪里配置我的 graphql 端点?我在他们的商店中看到了一些配置它的示例。我的商店稍微分成了 store.js 和 index.js 但如下:

// index.js

import React from 'react';
import ReactDOM from 'react-dom';
import  Provider  from 'react-redux';
import  BrowserRouter  from 'react-router-dom';

import App from './containers/App/App';

import initialState from './initialState';
import configureStore from './store';

import  ApolloClient, ApolloProvider  from 'react-apollo';

const client = new ApolloClient();

// Let the reducers handle initial state

initState() // eslint-disable-line

// if we are in production mode, we get the initial state from the window object, otherwise, when we are in dev env we get it from a static file
const preloadedState = window.__INITIAL_STATE__ === '__PRELOADEDSTATE__' ? initialState : window.__INITIAL_STATE__

const store = configureStore(preloadedState)

ReactDOM.render(
  <ApolloProvider store=store client=client>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </ApolloProvider>,
  document.getElementById('root')
)

// store.js

import  createStore, applyMiddleware, compose  from 'redux'
import  createLogger  from 'redux-logger'
import reducers from './reducers'
import  ApolloClient  from 'react-apollo';

const logger = createLogger()
const client = new ApolloClient();

export default function configureStore(initialState = ) 

  // Create the store with two middlewares
  const middlewares = [
  //  sagaMiddleware
    logger,
    client.middleware()
  ]

  const enhancers = [
    applyMiddleware(...middlewares)
  ]

  const store = createStore(
    reducers,
    initialState,
    compose(...enhancers)
  )

  // Extensions
  store.asyncReducers =  // Async reducer registry

  return store

更新

我现在正在从我的商店导入我的客户,因此我只有一个客户实例。我也使用/graphql 作为我的端点,所以我不需要配置端点。

// index.js

import React from 'react';
import ReactDOM from 'react-dom';
import  Provider  from 'react-redux';
import  BrowserRouter  from 'react-router-dom';

import App from './containers/App/App';

import initialState from './initialState';
import configureStore, client from './store';

import  ApolloClient, ApolloProvider  from 'react-apollo';

initState() // eslint-disable-line

// if we are in production mode, we get the initial state from the window object, otherwise, when we are in dev env we get it from a static file
const preloadedState = window.__INITIAL_STATE__ === '__PRELOADEDSTATE__' ? initialState : window.__INITIAL_STATE__

const store = configureStore(preloadedState)

ReactDOM.render(
  <ApolloProvider store=store client=client>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </ApolloProvider>,
  document.getElementById('root')
)

graphql(MY_QUERY, props: mapQueryToProps )(Home)还是有点疑惑

我有一个查询来获取在 graphiql 中工作的 curPage:(我猜 MY_QUERY 应该等于这个?)

query 
  findResource(filter: resource: "pages", slug: "about") 
    id
    title
    slug
    path
    sections
  

然后返回:


  "data": 
    "findResource": [
      
        "id": "5",
        "title": "About",
        "slug": "about",
        "path": "/about",
        "sections": [
          
            "type": "masthead",
            "mh_title": "",
            "video": false,
            "image": [],
            "showCta": false,
            "cta": []
          ,
          
            "type": "text_image",
            "alignment": "left",
            "text_image": [
              
                "type": "text",
                "title": "",
                "content": "",
                "call_to_action": false,
                "cta": []
              
            ]
          
        ]
      
    ]
  

这是否意味着我的

const mapQueryToProps = (data:  getPage:  page  , ownProps) => ( curPage: page ) 

应该看起来像:

const mapQueryToProps = (data:  findResource:  page  , ownProps) => ( curPage: page )

【问题讨论】:

【参考方案1】:

几个点:

您正在创建两个 ApolloClient 实例——一个在 index.js 中,一个在 store.js 中——你可以将客户端传递给 configureStore,这样你就可以使用同一个实例。

如果您的 graphQL 端点位于 /graphql 以外的任何位置,则您必须使用自定义网络接口。 Example from the docs:

import  ApolloClient, createNetworkInterface  from 'react-apollo';
const networkInterface = createNetworkInterface(
  uri: 'http://api.example.com/graphql'
);
const client = new ApolloClient( networkInterface );

只需进行最低限度的设置,查询中的数据将不会立即可用 - 一旦数据可用,组件将安装并重新呈现。但是,the documentation provides a couple of ways to get around that。

就查询数据如何映射到 props 而言,需要注意的是,Apollo 没有使用connect,而是有自己的 HOC。您将以类似的方式使用它:

graphql(MY_QUERY,  props: mapQueryToProps )(Home)

你分配给 props 的函数将被传递一个具有两个属性的对象,dataownProps。数据包括您的查询结果,而 ownProps 指的是组件上的任何现有道具。所以你的 mapQueryToProps 可能看起来像:

const mapQueryToProps = (data:  getPage:  page  , ownProps) =>
  ( curPage: page )

您也可以完全省略指定props,而您将获得整个data 对象作为道具。以上只是微调实际分配给组件的道具的一种方式。

如果您仍然想继续使用 redux 的部分状态,文档中有一个部分用于集成 redux 和 Apollo。如果您使用 compose 或 recompose,它非常干净。

Apollo 的 react 文档非常清晰和中肯。如果您还没有,您可能只想浏览Setup and optionsUsage 部分,甚至可能需要浏览任何适用的Recipes,然后再继续。

编辑:您传递给 HOC 的查询需要是一个字符串。最简单的做法是导入并使用gql 标签。根据您提供的查询,它看起来像这样:

const MY_QUERY = gql`
  query 
    findResource(filter: resource: "pages", slug: "about") 
      id
      title
      slug
      path
      sections
    
  `

【讨论】:

好的,我已根据您的建议对客户端进行了更改。我已经用我这样做的方式更新了我的原始帖子。其次,我仍然有点不确定如何映射QueryToProps。我已经用另一个例子更新了我的原始帖子。我在正确的轨道上吗?我也阅读了您建议的文档。 查看我的编辑以了解如何传递查询。你可以阅读更多here。至于 mapQueryToProps ......在我的例子中,我只是在猜测你的数据结构是什么;查看查询返回的内容——这就是您在 mapQueryToProps 中使用的数据对象。我猜您需要返回的数组中的第一个对象,因此您可以执行以下操作: (data) => (curPage: data.findResource[0])。 或者不要担心为这样的简单案例设置道具。只需执行graphql(MY_QUERY)(Home),然后您就可以使用props.data 访问组件内的数据。可能不那么令人头疼。 知道我为什么会收到Invariant Violation: Could not find "client" in the context of "Apollo(Home)". Wrap the root component in an &lt;ApolloProvider&gt; 吗?正如您在我的 index.js 中看到的,我将 App 包装在 &lt;ApolloProvider&gt;

以上是关于在 React 中使用 Apollo.js 将查询映射到道具的主要内容,如果未能解决你的问题,请参考以下文章

带有 NEST.JS 的 newrelic/apollo-server-plugin

将 Config.skip 与 React-Apollo 查询一起使用

React-Apollo,不要在组件加载时运行查询

Apollo js 订阅乐观 UI

@media 在一个非常奇怪的 React 实现中使用 .tsx 和 .ts 文件进行查询

React - Apollo,如何将 Object 放入查询中?