Last active
October 19, 2022 06:52
-
-
Save jonesaustindev/f0cecd461e5775e6decd75c338aac994 to your computer and use it in GitHub Desktop.
React Native + Apollo Client - Offline Mutations (Blog post: https://teamairship.com/offline-first-approach-for-mobile-apps-react-native-and-apollo/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import AsyncStorage from '@react-native-community/async-storage'; | |
import { persistCache } from 'apollo-cache-persist'; | |
import { | |
ApolloClient, | |
ApolloLink, | |
createHttpLink, | |
InMemoryCache, | |
} from '@apollo/client'; | |
import Config from 'react-native-config'; | |
import { setContext } from '@apollo/client/link/context'; | |
const uri = Config.API_URL; | |
export const getApolloClient = async (token, queueLink) => { | |
const cache = new InMemoryCache({}); | |
const httpLink = createHttpLink({ | |
uri, | |
}); | |
const authLink = setContext((_, { headers }) => { | |
return { | |
headers: { | |
...headers, | |
authorization: token ? `Bearer ${token}` : '', | |
}, | |
}; | |
}); | |
const link = ApolloLink.from([ | |
queueLink, | |
authLink, | |
httpLink, | |
]); | |
await persistCache({ | |
cache, | |
storage, | |
}); | |
return new ApolloClient({ cache, link }); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { useState, useEffect } from 'react'; | |
import { View, Text } from 'react-native'; | |
import { ApolloProvider } from '@apollo/client'; | |
import NetInfo from '@react-native-community/netinfo'; | |
import QueueLink from 'apollo-link-queue'; | |
import AsyncStorage from '@react-native-community/async-storage'; | |
import { getApolloClient } from '../apollo/apolloClient'; | |
import NoteView from './NoteView'; | |
const getToken = async () => { | |
return await AsyncStorage.getItem('@auth_token'); | |
}; | |
const queueLink = new QueueLink(); | |
const App = () => { | |
const [client, setClient] = useState(null); | |
const initializeApolloClient = async () => { | |
await getToken().then(async (authToken) => { | |
if (authToken) { | |
await getApolloClient(authToken, queueLink).then((apolloClient) => { | |
setClient(apolloClient); | |
}); | |
} | |
}); | |
}; | |
useEffect(() => { | |
const unsubscribe = NetInfo.addEventListener((state) => { | |
if (state.isConnected) { | |
queueLink.open(); | |
} else { | |
queueLink.close(); | |
} | |
}); | |
return () => unsubscribe(); | |
}, []); | |
useEffect(() => { | |
initializeApolloClient(); | |
}, []); | |
if (!client) { | |
return ( | |
<View> | |
<Text>Loading...</Text> | |
</View> | |
); | |
} | |
return ( | |
<ApolloProvider client={client}> | |
<NoteView /> | |
</ApolloProvider> | |
); | |
}; | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Imports | |
const GET_NOTES = gql` | |
query GetNotes($employeeId: ID!) { | |
notes(employeeId: $employeeId) { | |
nodes { | |
content | |
id | |
name | |
} | |
} | |
} | |
`; | |
const NoteView = () => { | |
// ... | |
const [ | |
createNote, | |
{ error: createError, data: createData, loading: createLoading }, | |
] = useMutation(CREATE_NOTE, { | |
// The note variable is defined by the server I am connected to. | |
// Input your variables here | |
variables: { | |
note: { | |
employeeId: employee.id, | |
name: noteName, | |
content: noteContent, | |
}, | |
}, | |
optimisticResponse: { | |
__typeName: 'Mutation', | |
createNote: { | |
__typename: 'CreateNotePayload', | |
note: { | |
__typeName: 'Note', | |
// Input your variables here | |
id: getUniqueId(), | |
name: noteName, | |
content: noteContent, | |
}, | |
errors: [], | |
}, | |
}, | |
update: (cache, { data }) => { | |
try { | |
const readData: any = cache.readQuery({ | |
query: GET_NOTES, | |
variables: { employeeId: employee.id }, | |
}); | |
let mergedNotes = []; | |
if (readData.notes.nodes.length <= 0) { | |
mergedNotes = [data.createNote.note]; | |
} else { | |
mergedNotes = [ | |
data.createNote.note, | |
...readData.notes.nodes, | |
]; | |
} | |
cache.writeQuery({ | |
query: GET_NOTES, | |
variables: { employeeId: employee.id }, | |
data: { | |
// this data object is the same as the one in the gql query above | |
...readData, | |
notes: { | |
nodes: mergedNotes, | |
}, | |
}, | |
}); | |
} catch (e) { | |
console.log({ e }); | |
} | |
}, | |
}); | |
// ... | |
} | |
export default NoteView; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Blog post: https://teamairship.com/offline-first-approach-for-mobile-apps-react-native-and-apollo/