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

时间:2017-07-17 23:17:37

标签: node.js reactjs redux graphql apollo

我刚刚在我的服务器上设置了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)

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

这是否向我的/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 个答案:

答案 0 :(得分:3)

几点:

您正在创建两个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

至于查询数据如何映射到道具,重要的是要注意Apollo不使用connect,而是拥有自己的HOC。您将以类似的方式使用它:

graphql(MY_QUERY, { props: mapQueryToProps })(Home)

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

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

您也可以省略完全指定props,并且您只需将整个data对象作为道具。以上只是一种微调实际被分配为组件道具的方法。

如果您的州仍然有部分要继续使用redux,那么在docs中有一个用于集成redux和Apollo的部分。如果你使用compose或recompose,它会非常干净。

Apollo的反应文件非常清楚,非常明确。如果您还没有,您可能只需浏览Setup and optionsUsage部分,甚至可以通过任何适用的Recipes,然后再继续。

编辑:您传递给HOC的查询需要是一个字符串。最简单的方法是导入并使用gql标记。根据您提供的查询,它将如下所示:

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