Skip to content

Commit

Permalink
Merge pull request #413 from wodCZ/feature/react-native-example
Browse files Browse the repository at this point in the history
update examples, fix hooks example in readme
  • Loading branch information
wtrocki authored Jan 9, 2021
2 parents 80b49aa + c9453d3 commit 6262373
Show file tree
Hide file tree
Showing 10 changed files with 1,273 additions and 823 deletions.
130 changes: 38 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ short debounce interval).
#### React Native

```js
import AsyncStorage from '@react-native-community/async-storage';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { InMemoryCache } from '@apollo/client/core';
import { persistCache, AsyncStorageWrapper } from 'apollo3-cache-persist';

Expand All @@ -42,6 +42,8 @@ const client = new ApolloClient({
});
```

See a complete example in the [React Native example](./examples/react-native/App.tsx).

#### Web

```js
Expand All @@ -64,6 +66,8 @@ const client = new ApolloClient({
});
```

See a complete example in the [web example](./examples/web/src/index.tsx).

### Additional Options

`persistCache` and the constructor for `CachePersistor` accept the following
Expand Down Expand Up @@ -223,7 +227,7 @@ If you found that stable version of supported provider is no-longer compatible,
#### Why is the 'background' trigger only available for React Native?
Quite simply, because mobile apps are different than web apps.
Quite simply, because mobile apps are different from web apps.
Mobile apps are rarely terminated before transitioning to the background. This
is helped by the fact that an app is moved to the background whenever the user
Expand All @@ -246,102 +250,44 @@ This library, like Apollo Client, is framework agnostic; however, since many
people have asked, here's an example of how to handle this in React. PRs with
examples from other frameworks are welcome.
##### React
```js
import React, { Component } from 'react';
import { ApolloProvider } from '@apollo/client/react';
import { InMemoryCache } from '@apollo/client/core';
import { persistCache, LocalStorageWrapper } from 'apollo3-cache-persist';

class App extends Component {
state = {
client: null,
loaded: false,
};

async componentDidMount() {
const cache = new InMemoryCache({...});

// Setup your Apollo Link, and any other Apollo packages here.

const client = new ApolloClient({
cache,
...
});

try {
// See above for additional options, including other storage providers.
await persistCache({
cache,
storage: new LocalStorageWrapper(window.localStorage),
});
} catch (error) {
console.error('Error restoring Apollo cache', error);
}

this.setState({
client,
loaded: true,
});
}

render() {
const { client, loaded } = this.state;

if (!loaded) {
return <div>Loading...</div>;
}

return (
<ApolloProvider client={client}>
{/* the rest of your app goes here */}
</ApolloProvider>
);
}
}
```
You can find all examples in the [examples](./examples/) directory.
##### React Using Hooks
```js
import React,{ useState, useEffect } from 'react';
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from '@apollo/client/core';
import { ApolloProvider } from "@apollo/react-hooks"
import { persistCache, LocalStorageWrapper } from 'apollo3-cache-persist';
import React, {useEffect, useState} from 'react';

import {ApolloClient, ApolloProvider,} from '@apollo/client';
import {InMemoryCache} from '@apollo/client/core';
import {LocalStorageWrapper, persistCache} from 'apollo3-cache-persist';

const App = () => {
const [client, setClient] = useState();

useEffect(() => {
async function init() {
const cache = new InMemoryCache();
await persistCache({
cache,
storage: new LocalStorageWrapper(window.localStorage),
})
setClient(
new ApolloClient({
cache,
}),
);
}

init().catch(console.error);
}, []);

const App: React.FC = () => {
const [client, setClient] = useState(undefined);
useEffect(() => {
const cache = new InMemoryCache({...});

const client = new ApolloClient({
cache,
...
});
const initData = {
{/* your initial data */}
};
cache.writeData({ data: initData })

// See above for additional options, including other storage providers.
persistCache({
cache,
storage: new LocalStorageWrapper(window.localStorage)
}).then(() => {
client.onResetStore(async () => cache.writeData({ data: initData }));
setClient(client);
});
return () => {};
}, []);
if (client === undefined) return <div>Loading...</div>;
return (
<ApolloProvider client={client}>
{/* the rest of your app goes here */}
</ApolloProvider>
);
return (
<ApolloProvider client={client}>
{/* the rest of your app goes here */}
</ApolloProvider>
);
};

export default App;
```

Expand Down
182 changes: 128 additions & 54 deletions examples/react-native/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,81 +8,155 @@
* @format
*/

import React, { useEffect, useState } from 'react';
import { SafeAreaView, StyleSheet, ScrollView, Text } from 'react-native';
import { ApolloClient, InMemoryCache } from '@apollo/client';
import { persistCache, AsyncStorageWrapper } from 'apollo3-cache-persist';
import AsyncStorage from '@react-native-community/async-storage';
import { gql } from '@apollo/client';
import React, {useCallback, useEffect, useState} from 'react';
import {
Button,
DevSettings,
SafeAreaView,
ScrollView,
StyleSheet,
Text,
View,
} from 'react-native';
import {
ApolloClient,
ApolloProvider,
gql,
InMemoryCache,
NormalizedCacheObject,
useQuery,
} from '@apollo/client';
import {AsyncStorageWrapper, CachePersistor} from 'apollo3-cache-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';

import { Colors } from 'react-native/Libraries/NewAppScreen';
const launchesGQL = gql`
query LaunchesQuery {
launches(limit: 10) {
id
mission_name
details
launch_date_utc
}
}
`;

type LaunchesQuery = {
launches: {
id: string;
mission_name: string;
details: string;
launch_date_utc: string;
}[];
};

const Launches = () => {
const {error, data, loading} = useQuery<LaunchesQuery>(launchesGQL, {
fetchPolicy: 'cache-and-network',
});

if (!data) {
// we don't have data yet

if (loading) {
// but we're loading some
return <Text style={styles.heading}>Loading initial data...</Text>;
}
if (error) {
// and we have an error
return <Text style={styles.heading}>Error loading data :(</Text>;
}
return <Text style={styles.heading}>Unknown error :(</Text>;
}

return (
<ScrollView>
{loading ? (
<Text style={styles.heading}>Loading fresh data...</Text>
) : null}
{data.launches.map(launch => (
<View key={launch.id} style={styles.item}>
<Text style={styles.mission}>{launch.mission_name}</Text>
<Text style={styles.launchDate}>
{new Date(launch.launch_date_utc).toLocaleString()}
</Text>
</View>
))}
</ScrollView>
);
};

const App = () => {
const [currencies, setCurrencies] = useState([]);
const [error, setError] = useState('');
const [client, setClient] = useState<ApolloClient<NormalizedCacheObject>>();
const [persistor, setPersistor] = useState<
CachePersistor<NormalizedCacheObject>
>();

useEffect(() => {
async function init() {
const cache = new InMemoryCache();
await persistCache({
let newPersistor = new CachePersistor({
cache,
storage: new AsyncStorageWrapper(AsyncStorage),
debug: __DEV__,
trigger: 'write',
});
const client = new ApolloClient({
uri: 'https://48p1r2roz4.sse.codesandbox.io',
cache: new InMemoryCache(),
});
try {
const { data } = await client.query({
query: gql`
query GetRates {
rates(currency: "USD") {
currency
}
}
`,
});

//@ts-ignore type this
setCurrencies(data.rates);
} catch (e) {
setError(e.message);
}
await newPersistor.restore();
setPersistor(newPersistor);
setClient(
new ApolloClient({
uri: 'https://api.spacex.land/graphql',
cache,
}),
);
}

init();
}, []);

const clearCache = useCallback(() => {
if (!persistor) {
return;
}
persistor.purge();
}, [persistor]);

const reload = useCallback(() => {
DevSettings.reload();
}, []);

if (!client) {
return <Text style={styles.heading}>Initializing app...</Text>;
}

return (
<>
<SafeAreaView>
{error ? (
<Text style={{ padding: 16, fontWeight: 'bold' }}>{error}</Text>
) : (
<>
<Text style={{ padding: 16, fontWeight: 'bold' }}>
List of currencies
</Text>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
{currencies.map((item: any, index: any) => (
//@ts-ignore type it
<Text key={item.currency + String(index)} style={{ padding: 16 }}>
{item.currency}
</Text>
))}
</ScrollView>
</>
)}
<ApolloProvider client={client}>
<SafeAreaView style={{...StyleSheet.absoluteFillObject}}>
<View style={styles.content}>
<Launches />
</View>
<View style={styles.controls}>
<Button title={'Clear cache'} onPress={clearCache} />
<Button title={'Reload app (requires dev mode)'} onPress={reload} />
</View>
</SafeAreaView>
</>
</ApolloProvider>
);
};

const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
heading: {
padding: 16,
fontWeight: 'bold',
},
item: {
padding: 16,
},
mission: {},
launchDate: {
fontSize: 12,
},
content: {flex: 1},
controls: {flex: 0},
});

export default App;
2 changes: 1 addition & 1 deletion examples/react-native/android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ android.useAndroidX=true
android.enableJetifier=true

# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.37.0
FLIPPER_VERSION=0.54.0
Loading

0 comments on commit 6262373

Please sign in to comment.