在 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 的函数将被传递一个具有两个属性的对象,data
和 ownProps
。数据包括您的查询结果,而 ownProps 指的是组件上的任何现有道具。所以你的 mapQueryToProps 可能看起来像:
const mapQueryToProps = (data: getPage: page , ownProps) =>
( curPage: page )
您也可以完全省略指定props
,而您将获得整个data
对象作为道具。以上只是微调实际分配给组件的道具的一种方式。
如果您仍然想继续使用 redux 的部分状态,文档中有一个部分用于集成 redux 和 Apollo。如果您使用 compose 或 recompose,它非常干净。
Apollo 的 react 文档非常清晰和中肯。如果您还没有,您可能只想浏览Setup and options
和Usage
部分,甚至可能需要浏览任何适用的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 <ApolloProvider>
吗?正如您在我的 index.js 中看到的,我将 App
包装在 <ApolloProvider>
以上是关于在 React 中使用 Apollo.js 将查询映射到道具的主要内容,如果未能解决你的问题,请参考以下文章
带有 NEST.JS 的 newrelic/apollo-server-plugin
将 Config.skip 与 React-Apollo 查询一起使用