Detect new todos - integration
Go to src/screens/components/Todos
.
For running a custom subscription, we need access to our ApolloClient
instance. To do that, we convert our Todos
component into an Apollo HOC by wrapping it in withApollo
.
+ import { withApollo } from 'react-apollo'// Todos.js- export default Todos;+ export default withApollo(Todos);
Once the component is an Apollo HOC, you receive the instance of Apollo client as a prop called client
.
Now let us define our subscription at the top level:
+const SUBSCRIBE_TO_NEW_TODOS = gql`+subscription {+ todos (+ order_by: {+ created_at: desc+ }+ limit: 1+ where: { is_public: { _eq: true }}+ ) {+ id+ created_at+ }+}`;
Firstly, let us declare a boolean state variable that holds the information whether new todos exist in the database. Then, using the above subscription, lets write a function called subscribeToNewTodos
that subscribes to the last public todo in the database. We will start this subscription after the first mount of the Todos
component. We will use the useEffect
hook for this.
const Todos = ({ isPublic, ...props }) => {+ const [newTodosExist, setNewTodosExist] = React.useState(false)+ const subscribeToNewTodos = () => {+ const { client } = props;+ if (isPublic) {+ client.subscribe({+ query: SUBSCRIBE_TO_NEW_TODOS,+ }).subscribe({+ next: (event) => {+ if (event.data.todos.length) {+ let localData;+ try {+ localData = client.readQuery({+ query: FETCH_TODOS,+ variables: {+ isPublic: true,+ }+ });+ } catch (e) {+ return;+ }++ const lastId = localData.todos[0] ? localData.todos[0].id : 0;+ if (event.data.todos[0].id > lastId) {+ setNewTodosExist(true)+ }+ }+ },+ error: (err) => {+ console.error("err", err);+ }+ })+ }+ };+ React.useEffect(subscribeToNewTodos, []);}
The subscribeToNewTodos
does the following:
- Starts a subscription to the last todo in the database
- Whenever data is received, it looks at the todos in Apollo cache and checks if the todo received via subscription is newer than the newest todo in the cache.
- If the todo received in subscription data has
id
greater than theid
of the newest todo in the cache, it sets a local state saying{ newTodosExist: true }
If new todos exist, we wish to show a button, pressing which, new todos will be loaded. So edit the JSX like:
<View style={styles.container}>- <LoadNewer show={isPublic} styles={styles} isPublic={isPublic}/>+ <LoadNewer show={newTodosExist && isPublic} styles={styles} isPublic={isPublic}/><ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollViewContainer}><FlatListdata={data.todos}renderItem={({item}) => <TodoItem item={item} isPublic={isPublic}/>}keyExtractor={(item) => item.id.toString()}/><LoadOlderisPublic={isPublic}styles={styles}/></ScrollView></View>
If you check the app now, this button would be shown only if there are todos in the database newer than the local todos.
We also need to write a function to dismiss this button (when the new todos are loaded), just write a class level function in the Todos
component and pass it to the button.
+const dismissNewTodoBanner = () => {+ setNewTodosExist(false);+};
<View style={styles.container}>- <LoadNewer show={newTodosExist && isPublic} styles={styles} isPublic={isPublic}/>+ <LoadNewer show={newTodosExist && isPublic} toggleShow={dismissNewTodoBanner} styles={styles} isPublic={isPublic}/><ScrollView style={styles.scrollView} contentContainerStyle={styles.scrollViewContainer}><FlatListdata={data.todos}renderItem={({item}) => <TodoItem item={item} isPublic={isPublic}/>}keyExtractor={(item) => item.id.toString()}/><LoadOlderisPublic={isPublic}styles={styles}/></ScrollView></View>
Awesome! You are now detecting new todo updates from the backend.
Now lets make this button functional.
- Build apps and APIs 10x faster
- Built-in authorization and caching
- 8x more performant than hand-rolled APIs