mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Create separate Apollo example without Redux integration (#1483)
* Add minimal apollo example * Update apollo example README * Update apollo example demo link in README * Fix button styles * Fix show more button * Alias demo url * Include the data field on the Apollo store when hydrating * Revert * Include the data field on the Apollo store when hydrating per tpreusse's suggestion. * Add example to faq section in README * Sort by newest; Add active state to buttons * Make optimization suggestions * Use process.browser; inline props * Pass wrapped component's initial props into component heirarchy if they exist * Remove unnecessary sorting of array * Update Apollo example * Remove trailing comma * Update reduxRootKey * Remove unnecessary babelrc * Update with-apollo example - Remove use of deprecated 'reduxRootKey' option - Add loading indicator inside pagination button * Fix with-apollo example pagination; Pass initialState to ApolloClient * Split apollo example into two (one with and without Redux integration) * Rename createClient private function to _initClient * Set initialState default parameter inside initClient function * Remove redux dep from with-apollo example
This commit is contained in:
parent
102c20df2c
commit
c2036e1326
26
examples/with-apollo-and-redux/README.md
Normal file
26
examples/with-apollo-and-redux/README.md
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# Apollo & Redux Example
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
Download the example [or clone the repo](https://github.com/zeit/next.js):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-apollo-and-redux
|
||||||
|
cd with-apollo-and-redux
|
||||||
|
```
|
||||||
|
|
||||||
|
Install it and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download)):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
now
|
||||||
|
```
|
||||||
|
|
||||||
|
## The idea behind the example
|
||||||
|
By default, Apollo Client creates its own internal Redux store to manage queries and their results. If you are already using Redux for the rest of your app, [you can have the client integrate with your existing store instead](http://dev.apollodata.com/react/redux.html). This example is identical to the [`with-apollo`](https://github.com/zeit/next.js/tree/master/examples/with-apollo) with the exception of this Redux store integration.
|
40
examples/with-apollo-and-redux/components/App.js
Normal file
40
examples/with-apollo-and-redux/components/App.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
export default ({ children }) => (
|
||||||
|
<main>
|
||||||
|
{children}
|
||||||
|
<style jsx global>{`
|
||||||
|
* {
|
||||||
|
font-family: Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 25px 50px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #22BAD9;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
article {
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 650px;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
align-items: center;
|
||||||
|
background-color: #22BAD9;
|
||||||
|
border: 0;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
padding: 5px 7px;
|
||||||
|
}
|
||||||
|
button:active {
|
||||||
|
background-color: #1B9DB7;
|
||||||
|
transition: background-color .3s
|
||||||
|
}
|
||||||
|
button:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</main>
|
||||||
|
)
|
27
examples/with-apollo-and-redux/components/Header.js
Normal file
27
examples/with-apollo-and-redux/components/Header.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export default ({ pathname }) => (
|
||||||
|
<header>
|
||||||
|
<Link prefetch href='/'>
|
||||||
|
<a className={pathname === '/' && 'is-active'}>Home</a>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<Link prefetch href='/about'>
|
||||||
|
<a className={pathname === '/about' && 'is-active'}>About</a>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<style jsx>{`
|
||||||
|
header {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 15px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.is-active {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</header>
|
||||||
|
)
|
110
examples/with-apollo-and-redux/components/PostList.js
Normal file
110
examples/with-apollo-and-redux/components/PostList.js
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import { gql, graphql } from 'react-apollo'
|
||||||
|
import PostUpvoter from './PostUpvoter'
|
||||||
|
|
||||||
|
const POSTS_PER_PAGE = 10
|
||||||
|
|
||||||
|
function PostList ({ data: { allPosts, loading, _allPostsMeta }, loadMorePosts }) {
|
||||||
|
if (allPosts && allPosts.length) {
|
||||||
|
const areMorePosts = allPosts.length < _allPostsMeta.count
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<ul>
|
||||||
|
{allPosts.map((post, index) =>
|
||||||
|
<li key={post.id}>
|
||||||
|
<div>
|
||||||
|
<span>{index + 1}. </span>
|
||||||
|
<a href={post.url}>{post.title}</a>
|
||||||
|
<PostUpvoter id={post.id} votes={post.votes} />
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
{areMorePosts ? <button onClick={() => loadMorePosts()}> {loading ? 'Loading...' : 'Show More'} </button> : ''}
|
||||||
|
<style jsx>{`
|
||||||
|
section {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
padding-bottom: 0;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
button:before {
|
||||||
|
align-self: center;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 6px 4px 0 4px;
|
||||||
|
border-color: #ffffff transparent transparent transparent;
|
||||||
|
content: "";
|
||||||
|
height: 0;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return <div>Loading</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
const allPosts = gql`
|
||||||
|
query allPosts($first: Int!, $skip: Int!) {
|
||||||
|
allPosts(orderBy: createdAt_DESC, first: $first, skip: $skip) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
votes
|
||||||
|
url
|
||||||
|
createdAt
|
||||||
|
},
|
||||||
|
_allPostsMeta {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// The `graphql` wrapper executes a GraphQL query and makes the results
|
||||||
|
// available on the `data` prop of the wrapped component (PostList)
|
||||||
|
export default graphql(allPosts, {
|
||||||
|
options: {
|
||||||
|
variables: {
|
||||||
|
skip: 0,
|
||||||
|
first: POSTS_PER_PAGE
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: ({ data }) => ({
|
||||||
|
data,
|
||||||
|
loadMorePosts: () => {
|
||||||
|
return data.fetchMore({
|
||||||
|
variables: {
|
||||||
|
skip: data.allPosts.length
|
||||||
|
},
|
||||||
|
updateQuery: (previousResult, { fetchMoreResult }) => {
|
||||||
|
if (!fetchMoreResult) {
|
||||||
|
return previousResult
|
||||||
|
}
|
||||||
|
return Object.assign({}, previousResult, {
|
||||||
|
// Append the new posts results to the old one
|
||||||
|
allPosts: [...previousResult.allPosts, ...fetchMoreResult.allPosts]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})(PostList)
|
53
examples/with-apollo-and-redux/components/PostUpvoter.js
Normal file
53
examples/with-apollo-and-redux/components/PostUpvoter.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { gql, graphql } from 'react-apollo'
|
||||||
|
|
||||||
|
function PostUpvoter ({ upvote, votes, id }) {
|
||||||
|
return (
|
||||||
|
<button onClick={() => upvote(id, votes + 1)}>
|
||||||
|
{votes}
|
||||||
|
<style jsx>{`
|
||||||
|
button {
|
||||||
|
background-color: transparent;
|
||||||
|
border: 1px solid #e4e4e4;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
button:active {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
button:before {
|
||||||
|
align-self: center;
|
||||||
|
border-color: transparent transparent #000000 transparent;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 0 4px 6px 4px;
|
||||||
|
content: "";
|
||||||
|
height: 0;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const upvotePost = gql`
|
||||||
|
mutation updatePost($id: ID!, $votes: Int) {
|
||||||
|
updatePost(id: $id, votes: $votes) {
|
||||||
|
id
|
||||||
|
votes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default graphql(upvotePost, {
|
||||||
|
props: ({ ownProps, mutate }) => ({
|
||||||
|
upvote: (id, votes) => mutate({
|
||||||
|
variables: { id, votes },
|
||||||
|
optimisticResponse: {
|
||||||
|
updatePost: {
|
||||||
|
id: ownProps.id,
|
||||||
|
votes: ownProps.votes + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})(PostUpvoter)
|
78
examples/with-apollo-and-redux/components/Submit.js
Normal file
78
examples/with-apollo-and-redux/components/Submit.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import { gql, graphql } from 'react-apollo'
|
||||||
|
|
||||||
|
function Submit ({ createPost }) {
|
||||||
|
function handleSubmit (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
let title = e.target.elements.title.value
|
||||||
|
let url = e.target.elements.url.value
|
||||||
|
|
||||||
|
if (title === '' || url === '') {
|
||||||
|
window.alert('Both fields are required.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepend http if missing from url
|
||||||
|
if (!url.match(/^[a-zA-Z]+:\/\//)) {
|
||||||
|
url = `http://${url}`
|
||||||
|
}
|
||||||
|
|
||||||
|
createPost(title, url)
|
||||||
|
|
||||||
|
// reset form
|
||||||
|
e.target.elements.title.value = ''
|
||||||
|
e.target.elements.url.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<h1>Submit</h1>
|
||||||
|
<input placeholder='title' name='title' />
|
||||||
|
<input placeholder='url' name='url' />
|
||||||
|
<button type='submit'>Submit</button>
|
||||||
|
<style jsx>{`
|
||||||
|
form {
|
||||||
|
border-bottom: 1px solid #ececec;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createPost = gql`
|
||||||
|
mutation createPost($title: String!, $url: String!) {
|
||||||
|
createPost(title: $title, url: $url) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
votes
|
||||||
|
url
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default graphql(createPost, {
|
||||||
|
props: ({ mutate }) => ({
|
||||||
|
createPost: (title, url) => mutate({
|
||||||
|
variables: { title, url },
|
||||||
|
updateQueries: {
|
||||||
|
allPosts: (previousResult, { mutationResult }) => {
|
||||||
|
const newPost = mutationResult.data.createPost
|
||||||
|
return Object.assign({}, previousResult, {
|
||||||
|
// Append the new post
|
||||||
|
allPosts: [newPost, ...previousResult.allPosts]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})(Submit)
|
28
examples/with-apollo-and-redux/lib/initClient.js
Normal file
28
examples/with-apollo-and-redux/lib/initClient.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { ApolloClient, createNetworkInterface } from 'react-apollo'
|
||||||
|
|
||||||
|
let apolloClient = null
|
||||||
|
|
||||||
|
function _initClient (headers, initialState) {
|
||||||
|
return new ApolloClient({
|
||||||
|
initialState,
|
||||||
|
ssrMode: !process.browser,
|
||||||
|
dataIdFromObject: result => result.id || null,
|
||||||
|
networkInterface: createNetworkInterface({
|
||||||
|
uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn',
|
||||||
|
opts: {
|
||||||
|
credentials: 'same-origin'
|
||||||
|
// Pass headers here if your graphql server requires them
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const initClient = (headers, initialState = {}) => {
|
||||||
|
if (!process.browser) {
|
||||||
|
return _initClient(headers, initialState)
|
||||||
|
}
|
||||||
|
if (!apolloClient) {
|
||||||
|
apolloClient = _initClient(headers, initialState)
|
||||||
|
}
|
||||||
|
return apolloClient
|
||||||
|
}
|
56
examples/with-apollo-and-redux/lib/withData.js
Normal file
56
examples/with-apollo-and-redux/lib/withData.js
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import 'isomorphic-fetch'
|
||||||
|
import React from 'react'
|
||||||
|
import { ApolloProvider, getDataFromTree } from 'react-apollo'
|
||||||
|
import { initClient } from './initClient'
|
||||||
|
import { initStore } from './initStore'
|
||||||
|
|
||||||
|
export default (Component) => (
|
||||||
|
class extends React.Component {
|
||||||
|
static async getInitialProps (ctx) {
|
||||||
|
const headers = ctx.req ? ctx.req.headers : {}
|
||||||
|
const client = initClient(headers)
|
||||||
|
const store = initStore(client, client.initialState)
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
url: { query: ctx.query, pathname: ctx.pathname },
|
||||||
|
...await (Component.getInitialProps ? Component.getInitialProps(ctx) : {})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!process.browser) {
|
||||||
|
const app = (
|
||||||
|
<ApolloProvider client={client} store={store}>
|
||||||
|
<Component {...props} />
|
||||||
|
</ApolloProvider>
|
||||||
|
)
|
||||||
|
await getDataFromTree(app)
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = store.getState()
|
||||||
|
|
||||||
|
return {
|
||||||
|
initialState: {
|
||||||
|
...state,
|
||||||
|
apollo: {
|
||||||
|
data: client.getInitialState().data
|
||||||
|
}
|
||||||
|
},
|
||||||
|
headers,
|
||||||
|
...props
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
this.client = initClient(this.props.headers, this.props.initialState)
|
||||||
|
this.store = initStore(this.client, this.props.initialState)
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<ApolloProvider client={this.client} store={this.store}>
|
||||||
|
<Component {...this.props} />
|
||||||
|
</ApolloProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
18
examples/with-apollo-and-redux/package.json
Normal file
18
examples/with-apollo-and-redux/package.json
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"name": "with-apollo-and-redux",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "next",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"graphql": "^0.9.1",
|
||||||
|
"next": "^2.0.0-beta",
|
||||||
|
"react": "^15.4.2",
|
||||||
|
"react-apollo": "^1.0.0-rc.2",
|
||||||
|
"redux": "^3.6.0"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
23
examples/with-apollo-and-redux/pages/about.js
Normal file
23
examples/with-apollo-and-redux/pages/about.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import App from '../components/App'
|
||||||
|
import Header from '../components/Header'
|
||||||
|
|
||||||
|
export default (props) => (
|
||||||
|
<App>
|
||||||
|
<Header pathname={props.url.pathname} />
|
||||||
|
<article>
|
||||||
|
<h1>The Idea Behind This Example</h1>
|
||||||
|
<p>
|
||||||
|
<a href='http://dev.apollodata.com'>Apollo</a> is a GraphQL client that allows you to easily query the exact data you need from a GraphQL server. In addition to fetching and mutating data, Apollo analyzes your queries and their results to construct a client-side cache of your data, which is kept up to date as further queries and mutations are run, fetching more results from the server.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In this simple example, we integrate Apollo seamlessly with <a href='https://github.com/zeit/next.js'>Next</a> by wrapping our pages inside a <a href='https://facebook.github.io/react/docs/higher-order-components.html'>higher-order component (HOC)</a>. Using the HOC pattern we're able to pass down a central store of query result data created by Apollo into our React component hierarchy defined inside each page of our Next application.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
On initial page load, while on the server and inside getInitialProps, we invoke the Apollo method, <a href='http://dev.apollodata.com/react/server-side-rendering.html#getDataFromTree'>getDataFromTree</a>. This method returns a promise; at the point in which the promise resolves, our Apollo Client store is completely initialized.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
This example relies on <a href='http://graph.cool'>graph.cool</a> for its GraphQL backend.
|
||||||
|
</p>
|
||||||
|
</article>
|
||||||
|
</App>
|
||||||
|
)
|
13
examples/with-apollo-and-redux/pages/index.js
Normal file
13
examples/with-apollo-and-redux/pages/index.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import App from '../components/App'
|
||||||
|
import Header from '../components/Header'
|
||||||
|
import Submit from '../components/Submit'
|
||||||
|
import PostList from '../components/PostList'
|
||||||
|
import withData from '../lib/withData'
|
||||||
|
|
||||||
|
export default withData((props) => (
|
||||||
|
<App>
|
||||||
|
<Header pathname={props.url.pathname} />
|
||||||
|
<Submit />
|
||||||
|
<PostList />
|
||||||
|
</App>
|
||||||
|
))
|
|
@ -35,3 +35,5 @@ In this simple example, we integrate Apollo seamlessly with Next by wrapping our
|
||||||
On initial page load, while on the server and inside `getInitialProps`, we invoke the Apollo method, [`getDataFromTree`](http://dev.apollodata.com/react/server-side-rendering.html#getDataFromTree). This method returns a promise; at the point in which the promise resolves, our Apollo Client store is completely initialized.
|
On initial page load, while on the server and inside `getInitialProps`, we invoke the Apollo method, [`getDataFromTree`](http://dev.apollodata.com/react/server-side-rendering.html#getDataFromTree). This method returns a promise; at the point in which the promise resolves, our Apollo Client store is completely initialized.
|
||||||
|
|
||||||
This example relies on [graph.cool](https://www.graph.cool) for its GraphQL backend.
|
This example relies on [graph.cool](https://www.graph.cool) for its GraphQL backend.
|
||||||
|
|
||||||
|
*Note: Apollo uses Redux internally; if you're interested in integrating the client with your existing Redux store check out the [`with-apollo-and-redux`](https://github.com/zeit/next.js/tree/master/examples/with-apollo-and-redux) example.*
|
||||||
|
|
|
@ -96,12 +96,12 @@ export default graphql(allPosts, {
|
||||||
skip: data.allPosts.length
|
skip: data.allPosts.length
|
||||||
},
|
},
|
||||||
updateQuery: (previousResult, { fetchMoreResult }) => {
|
updateQuery: (previousResult, { fetchMoreResult }) => {
|
||||||
if (!fetchMoreResult.data) {
|
if (!fetchMoreResult) {
|
||||||
return previousResult
|
return previousResult
|
||||||
}
|
}
|
||||||
return Object.assign({}, previousResult, {
|
return Object.assign({}, previousResult, {
|
||||||
// Append the new posts results to the old one
|
// Append the new posts results to the old one
|
||||||
allPosts: [...previousResult.allPosts, ...fetchMoreResult.data.allPosts]
|
allPosts: [...previousResult.allPosts, ...fetchMoreResult.allPosts]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,8 +2,9 @@ import { ApolloClient, createNetworkInterface } from 'react-apollo'
|
||||||
|
|
||||||
let apolloClient = null
|
let apolloClient = null
|
||||||
|
|
||||||
function createClient (headers) {
|
function _initClient (headers, initialState) {
|
||||||
return new ApolloClient({
|
return new ApolloClient({
|
||||||
|
initialState,
|
||||||
ssrMode: !process.browser,
|
ssrMode: !process.browser,
|
||||||
dataIdFromObject: result => result.id || null,
|
dataIdFromObject: result => result.id || null,
|
||||||
networkInterface: createNetworkInterface({
|
networkInterface: createNetworkInterface({
|
||||||
|
@ -16,12 +17,12 @@ function createClient (headers) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const initClient = (headers) => {
|
export const initClient = (headers, initialState = {}) => {
|
||||||
if (!process.browser) {
|
if (!process.browser) {
|
||||||
return createClient(headers)
|
return _initClient(headers, initialState)
|
||||||
}
|
}
|
||||||
if (!apolloClient) {
|
if (!apolloClient) {
|
||||||
apolloClient = createClient(headers)
|
apolloClient = _initClient(headers, initialState)
|
||||||
}
|
}
|
||||||
return apolloClient
|
return apolloClient
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,12 @@ import 'isomorphic-fetch'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ApolloProvider, getDataFromTree } from 'react-apollo'
|
import { ApolloProvider, getDataFromTree } from 'react-apollo'
|
||||||
import { initClient } from './initClient'
|
import { initClient } from './initClient'
|
||||||
import { initStore } from './initStore'
|
|
||||||
|
|
||||||
export default (Component) => (
|
export default (Component) => (
|
||||||
class extends React.Component {
|
class extends React.Component {
|
||||||
static async getInitialProps (ctx) {
|
static async getInitialProps (ctx) {
|
||||||
const headers = ctx.req ? ctx.req.headers : {}
|
const headers = ctx.req ? ctx.req.headers : {}
|
||||||
const client = initClient(headers)
|
const client = initClient(headers)
|
||||||
const store = initStore(client, client.initialState)
|
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
url: { query: ctx.query, pathname: ctx.pathname },
|
url: { query: ctx.query, pathname: ctx.pathname },
|
||||||
|
@ -18,18 +16,15 @@ export default (Component) => (
|
||||||
|
|
||||||
if (!process.browser) {
|
if (!process.browser) {
|
||||||
const app = (
|
const app = (
|
||||||
<ApolloProvider client={client} store={store}>
|
<ApolloProvider client={client}>
|
||||||
<Component {...props} />
|
<Component {...props} />
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
)
|
)
|
||||||
await getDataFromTree(app)
|
await getDataFromTree(app)
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = store.getState()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
initialState: {
|
initialState: {
|
||||||
...state,
|
|
||||||
apollo: {
|
apollo: {
|
||||||
data: client.getInitialState().data
|
data: client.getInitialState().data
|
||||||
}
|
}
|
||||||
|
@ -41,13 +36,12 @@ export default (Component) => (
|
||||||
|
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.client = initClient(this.props.headers)
|
this.client = initClient(this.props.headers, this.props.initialState)
|
||||||
this.store = initStore(this.client, this.props.initialState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<ApolloProvider client={this.client} store={this.store}>
|
<ApolloProvider client={this.client}>
|
||||||
<Component {...this.props} />
|
<Component {...this.props} />
|
||||||
</ApolloProvider>
|
</ApolloProvider>
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
"graphql": "^0.9.1",
|
"graphql": "^0.9.1",
|
||||||
"next": "^2.0.0-beta",
|
"next": "^2.0.0-beta",
|
||||||
"react": "^15.4.2",
|
"react": "^15.4.2",
|
||||||
"react-apollo": "^1.0.0-rc.2",
|
"react-apollo": "^1.0.0-rc.3"
|
||||||
"redux": "^3.6.0"
|
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
|
|
Loading…
Reference in a new issue