From ec2b76f83b72853b01ea6f497e32b501b0736354 Mon Sep 17 00:00:00 2001 From: Jayden Seric Date: Sun, 2 Jul 2017 07:56:12 +1000 Subject: [PATCH] Better data fetching error handling for Apollo examples (#2227) * Display data fetching errors in Apollo examples. * Prevent Apollo GraphQL errors from crashing SSR. Also tidied a few comments in the vicinity. --- .../components/ErrorMessage.js | 13 +++++++++ .../components/PostList.js | 4 ++- .../with-apollo-and-redux/lib/withData.js | 29 +++++++++++-------- .../with-apollo/components/ErrorMessage.js | 13 +++++++++ examples/with-apollo/components/PostList.js | 4 ++- examples/with-apollo/lib/withData.js | 28 +++++++++++------- 6 files changed, 66 insertions(+), 25 deletions(-) create mode 100644 examples/with-apollo-and-redux/components/ErrorMessage.js create mode 100644 examples/with-apollo/components/ErrorMessage.js diff --git a/examples/with-apollo-and-redux/components/ErrorMessage.js b/examples/with-apollo-and-redux/components/ErrorMessage.js new file mode 100644 index 00000000..c4a800c7 --- /dev/null +++ b/examples/with-apollo-and-redux/components/ErrorMessage.js @@ -0,0 +1,13 @@ +export default ({message}) => ( + +) diff --git a/examples/with-apollo-and-redux/components/PostList.js b/examples/with-apollo-and-redux/components/PostList.js index 36523648..59efbcfb 100644 --- a/examples/with-apollo-and-redux/components/PostList.js +++ b/examples/with-apollo-and-redux/components/PostList.js @@ -1,9 +1,11 @@ import { gql, graphql } from 'react-apollo' +import ErrorMessage from './ErrorMessage' import PostUpvoter from './PostUpvoter' const POSTS_PER_PAGE = 10 -function PostList ({ data: { allPosts, loading, _allPostsMeta }, loadMorePosts }) { +function PostList ({ data: { loading, error, allPosts, _allPostsMeta }, loadMorePosts }) { + if (error) return if (allPosts && allPosts.length) { const areMorePosts = allPosts.length < _allPostsMeta.count return ( diff --git a/examples/with-apollo-and-redux/lib/withData.js b/examples/with-apollo-and-redux/lib/withData.js index 6e629be0..d091c6f4 100644 --- a/examples/with-apollo-and-redux/lib/withData.js +++ b/examples/with-apollo-and-redux/lib/withData.js @@ -25,23 +25,28 @@ export default ComposedComponent => { composedInitialProps = await ComposedComponent.getInitialProps(ctx) } - // Run all graphql queries in the component tree + // Run all GraphQL queries in the component tree // and extract the resulting data if (!process.browser) { const apollo = initApollo() const redux = initRedux(apollo) - // Provide the `url` prop data in case a graphql query uses it + // Provide the `url` prop data in case a GraphQL query uses it const url = {query: ctx.query, pathname: ctx.pathname} - // Run all graphql queries - const app = ( - // No need to use the Redux Provider - // because Apollo sets up the store for us - - - - ) - await getDataFromTree(app) + try { + // Run all GraphQL queries + await getDataFromTree( + // No need to use the Redux Provider + // because Apollo sets up the store for us + + + + ) + } catch (error) { + // Prevent Apollo Client GraphQL errors from crashing SSR. + // Handle them in components via the data.error prop: + // http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error + } // Extract query data from the store const state = redux.getState() @@ -49,7 +54,7 @@ export default ComposedComponent => { // No need to include other initial Redux state because when it // initialises on the client-side it'll create it again anyway serverState = { - apollo: { // Make sure to only include Apollo's data state + apollo: { // Only include the Apollo data state data: state.apollo.data } } diff --git a/examples/with-apollo/components/ErrorMessage.js b/examples/with-apollo/components/ErrorMessage.js new file mode 100644 index 00000000..c4a800c7 --- /dev/null +++ b/examples/with-apollo/components/ErrorMessage.js @@ -0,0 +1,13 @@ +export default ({message}) => ( + +) diff --git a/examples/with-apollo/components/PostList.js b/examples/with-apollo/components/PostList.js index 36523648..59efbcfb 100644 --- a/examples/with-apollo/components/PostList.js +++ b/examples/with-apollo/components/PostList.js @@ -1,9 +1,11 @@ import { gql, graphql } from 'react-apollo' +import ErrorMessage from './ErrorMessage' import PostUpvoter from './PostUpvoter' const POSTS_PER_PAGE = 10 -function PostList ({ data: { allPosts, loading, _allPostsMeta }, loadMorePosts }) { +function PostList ({ data: { loading, error, allPosts, _allPostsMeta }, loadMorePosts }) { + if (error) return if (allPosts && allPosts.length) { const areMorePosts = allPosts.length < _allPostsMeta.count return ( diff --git a/examples/with-apollo/lib/withData.js b/examples/with-apollo/lib/withData.js index 1aeaa427..0127aa32 100644 --- a/examples/with-apollo/lib/withData.js +++ b/examples/with-apollo/lib/withData.js @@ -24,26 +24,32 @@ export default ComposedComponent => { composedInitialProps = await ComposedComponent.getInitialProps(ctx) } - // Run all graphql queries in the component tree + // Run all GraphQL queries in the component tree // and extract the resulting data if (!process.browser) { const apollo = initApollo() - // Provide the `url` prop data in case a graphql query uses it + // Provide the `url` prop data in case a GraphQL query uses it const url = {query: ctx.query, pathname: ctx.pathname} - // Run all graphql queries - const app = ( - - - - ) - await getDataFromTree(app) + try { + // Run all GraphQL queries + await getDataFromTree( + + + + ) + } catch (error) { + // Prevent Apollo Client GraphQL errors from crashing SSR. + // Handle them in components via the data.error prop: + // http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error + } - // Extract query data from the Apollo's store + // Extract query data from the Apollo store const state = apollo.getInitialState() serverState = { - apollo: { // Make sure to only include Apollo's data state + apollo: { + // Only include the Apollo data state data: state.data } }