├── assets
├── icon.png
├── favicon.png
├── splash.png
└── icon-ios.png
├── babel.config.js
├── .gitignore
├── .expo-shared
└── assets.json
├── src
├── Loading.js
├── styles.js
├── HomeScreen.js
└── ChapterScreen.js
├── CHANGELOG.md
├── app.json
├── package.json
├── README.md
└── App.js
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GraphQLGuide/guide-react-native/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GraphQLGuide/guide-react-native/HEAD/assets/favicon.png
--------------------------------------------------------------------------------
/assets/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GraphQLGuide/guide-react-native/HEAD/assets/splash.png
--------------------------------------------------------------------------------
/assets/icon-ios.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GraphQLGuide/guide-react-native/HEAD/assets/icon-ios.png
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true)
3 | return {
4 | presets: ['babel-preset-expo'],
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | *.jks
5 | *.p8
6 | *.p12
7 | *.key
8 | *.mobileprovision
9 | *.orig.*
10 | web-build/
11 |
12 | # macOS
13 | .DS_Store
14 |
--------------------------------------------------------------------------------
/.expo-shared/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "b16ca03b8ec79df78b00abe3deb7f10948ab7195933127afefd6a94bc516e36b": true,
3 | "b39052b09ee4b3f28ec0461d66b0b8b2f439d3f49112234912ac9d18ae9e0647": true,
4 | "7b1e2274ea18550cf3628c4b375960e859206bce3f70ca15c368638c3d4982c0": true
5 | }
6 |
--------------------------------------------------------------------------------
/src/Loading.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View, ActivityIndicator } from 'react-native'
3 |
4 | import styles, { PINK } from './styles'
5 |
6 | export default () => (
7 |
8 |
9 |
10 | )
11 |
--------------------------------------------------------------------------------
/src/styles.js:
--------------------------------------------------------------------------------
1 | import { StyleSheet } from 'react-native'
2 |
3 | export const PINK = '#ff5dc8'
4 |
5 | export const screenOptions = {
6 | headerStyle: {
7 | backgroundColor: PINK,
8 | },
9 | headerTintColor: '#fff',
10 | }
11 |
12 | export default StyleSheet.create({
13 | centered: {
14 | flex: 1,
15 | justifyContent: 'center',
16 | alignItems: 'center',
17 | },
18 | item: {
19 | paddingTop: 16,
20 | paddingBottom: 16,
21 | paddingLeft: 20,
22 | paddingRight: 20,
23 | borderBottomWidth: 1,
24 | borderBottomColor: '#cccccc',
25 | },
26 | header: {
27 | fontWeight: 'bold',
28 | },
29 | subheader: {
30 | paddingTop: 10,
31 | },
32 | })
33 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes will be documented in this file.
3 |
4 | This file applies to the app that is created in Chapter 8 of the book—so the numbered step branches, not `master`.
5 |
6 | Releases are done with tags in the form `[step]_[version]`, so for instance step `3` of version `1.0.0` is `3_1.0.0`, located here:
7 |
8 | [/GraphQLGuide/guide-android/releases/tag/3_1.0.0](https://github.com/GraphQLGuide/guide-android/releases/tag/3_1.0.0)
9 |
10 |
15 |
16 | ## [1.0.0] - 2021-04-06
17 | Released with [`r6`](https://github.com/GraphQLGuide/book/releases/tag/r6)
18 |
19 | ### Added
20 | - Branches `0-3`
21 |
22 | ```
23 | @apollo/client 3.2.1
24 | expo 39.0.2
25 | react 16.13.1
26 | ```
27 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "guide",
4 | "slug": "guide",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/icon.png",
8 | "primaryColor": "#ff5dc8",
9 | "splash": {
10 | "image": "./assets/splash.png",
11 | "resizeMode": "cover",
12 | "backgroundColor": "#ffffff"
13 | },
14 | "updates": {
15 | "fallbackToCacheTimeout": 0
16 | },
17 | "assetBundlePatterns": ["**/*"],
18 | "ios": {
19 | "bundleIdentifier": "guide.graphql.guide",
20 | "buildNumber": "1.0.0",
21 | "supportsTablet": true,
22 | "icon": "./assets/icon-ios.png"
23 | },
24 | "android": {
25 | "package": "guide.graphql.guide",
26 | "versionCode": 1,
27 | "permissions": []
28 | },
29 | "web": {
30 | "favicon": "./assets/favicon.png"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "node_modules/expo/AppEntry.js",
3 | "scripts": {
4 | "start": "expo start",
5 | "android": "expo start --android",
6 | "ios": "expo start --ios",
7 | "web": "expo start --web",
8 | "eject": "expo eject"
9 | },
10 | "dependencies": {
11 | "@apollo/client": "^3.2.1",
12 | "@react-native-community/async-storage": "^1.12.0",
13 | "@react-native-community/masked-view": "0.1.10",
14 | "@react-navigation/native": "^5.7.4",
15 | "@react-navigation/stack": "^5.9.1",
16 | "apollo3-cache-persist": "^0.6.0",
17 | "expo": "~39.0.2",
18 | "expo-status-bar": "~1.0.2",
19 | "graphql": "^15.3.0",
20 | "react": "16.13.1",
21 | "react-dom": "16.13.1",
22 | "react-native": "https://github.com/expo/react-native/archive/sdk-39.0.2.tar.gz",
23 | "react-native-gesture-handler": "~1.7.0",
24 | "react-native-reanimated": "~1.13.0",
25 | "react-native-safe-area-context": "3.1.4",
26 | "react-native-screens": "~2.10.1",
27 | "react-native-web": "~0.13.12"
28 | },
29 | "devDependencies": {
30 | "@babel/core": "~7.9.0"
31 | },
32 | "private": true
33 | }
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## The GraphQL Guide React Native app
2 |
3 | - Entry point: [App.js](https://github.com/GraphQLGuide/guide-react-native/blob/master/App.js)
4 | - Two screens, each with a GraphQL query:
5 | - [src/HomeScreen.js](https://github.com/GraphQLGuide/guide-react-native/blob/master/src/HomeScreen.js)
6 | - [src/ChapterScreen.js](https://github.com/GraphQLGuide/guide-react-native/blob/master/src/ChapterScreen.js)
7 |
8 | This example app is built, tutorial-style, in the React Native chapter of [The GraphQL Guide](https://graphql.guide/). Here are the tutorial steps:
9 |
10 | - [Starting branch: 0](https://github.com/GraphQLGuide/guide-react-native/tree/0) app skeleton
11 | - [Step 1: 0...1](https://github.com/GraphQLGuide/guide-react-native/compare/0...1) adding Apollo Client and first query
12 | - [Step 2: 1...2](https://github.com/GraphQLGuide/guide-react-native/compare/1...2) adding second screen and query
13 | - [Step 3: 2...3](https://github.com/GraphQLGuide/guide-react-native/compare/2...3) persisting the cache
14 |
15 | ### Running the app
16 |
17 | ```sh
18 | git clone https://github.com/GraphQLGuide/guide-react-native.git
19 | cd guide-react-native/
20 | npm install
21 | npm start
22 | ```
23 |
24 | This will start the Expo bundler, and you can open the app on Android, iOS, or web.
25 |
26 | 
27 |
--------------------------------------------------------------------------------
/src/HomeScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Text, FlatList, Pressable } from 'react-native'
3 | import { gql, useQuery } from '@apollo/client'
4 | import { AppLoading } from 'expo'
5 |
6 | import styles from './styles'
7 |
8 | const CHAPTERS_QUERY = gql`
9 | query Chapters {
10 | chapters {
11 | id
12 | number
13 | title
14 | }
15 | }
16 | `
17 |
18 | const ChapterItem = ({ chapter, onPress }) => {
19 | const { number, title } = chapter
20 | let header, subheader
21 |
22 | if (number) {
23 | header = `Chapter ${number}`
24 | subheader = title
25 | } else {
26 | header = title
27 | }
28 |
29 | return (
30 |
31 | {header}
32 | {subheader && {subheader}}
33 |
34 | )
35 | }
36 |
37 | export default ({ navigation }) => {
38 | const { data, loading } = useQuery(CHAPTERS_QUERY)
39 |
40 | if (loading) {
41 | return
42 | }
43 |
44 | return (
45 | (
48 | navigation.navigate('Chapter', { chapter: item })}
51 | />
52 | )}
53 | keyExtractor={(chapter) => chapter.id.toString()}
54 | />
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/src/ChapterScreen.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View, Text, FlatList } from 'react-native'
3 | import { gql, useQuery } from '@apollo/client'
4 |
5 | import styles from './styles'
6 | import Loading from './Loading'
7 |
8 | const SECTIONS_QUERY = gql`
9 | query Sections($id: Int!) {
10 | chapter(id: $id) {
11 | sections {
12 | number
13 | title
14 | }
15 | }
16 | }
17 | `
18 |
19 | const SectionItem = ({ section, chapter }) => (
20 |
21 |
22 | {chapter.number}.{section.number}: {section.title}
23 |
24 |
25 | )
26 |
27 | export default ({ route }) => {
28 | const { data, loading } = useQuery(SECTIONS_QUERY, {
29 | variables: { id: route.params.chapter.id },
30 | })
31 |
32 | if (loading) {
33 | return
34 | }
35 |
36 | const {
37 | chapter: { sections },
38 | } = data
39 |
40 | if (sections.length === 1) {
41 | return (
42 |
43 | No sections
44 |
45 | )
46 | }
47 |
48 | return (
49 | (
52 |
53 | )}
54 | keyExtractor={(section) => section.number.toString()}
55 | initialNumToRender={15}
56 | />
57 | )
58 | }
59 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { StatusBar } from 'expo-status-bar'
3 | import { NavigationContainer } from '@react-navigation/native'
4 | import { createStackNavigator } from '@react-navigation/stack'
5 | import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'
6 | import AsyncStorage from '@react-native-community/async-storage'
7 | import { persistCache } from 'apollo3-cache-persist'
8 | import { AppLoading } from 'expo'
9 |
10 | import HomeScreen from './src/HomeScreen'
11 | import ChapterScreen from './src/ChapterScreen'
12 | import { screenOptions } from './src/styles'
13 |
14 | const Stack = createStackNavigator()
15 |
16 | const cache = new InMemoryCache()
17 |
18 | const client = new ApolloClient({
19 | uri: 'https://api.graphql.guide/graphql',
20 | cache,
21 | defaultOptions: { watchQuery: { fetchPolicy: 'cache-and-network' } },
22 | })
23 |
24 | export default function App() {
25 | const [loadingCache, setLoadingCache] = useState(true)
26 |
27 | useEffect(() => {
28 | persistCache({
29 | cache,
30 | storage: AsyncStorage,
31 | }).then(() => setLoadingCache(false))
32 | }, [])
33 |
34 | if (loadingCache) {
35 | return
36 | }
37 |
38 | return (
39 |
40 |
41 |
42 |
47 | ({
57 | title: number ? `Chapter ${number}: ${title}` : title,
58 | gestureResponseDistance: { horizontal: 500 },
59 | })}
60 | />
61 |
62 |
63 |
64 |
65 | )
66 | }
67 |
--------------------------------------------------------------------------------