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.

githubTodos.js
+ 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:

  1. Starts a subscription to the last todo in the database
  2. 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.
  3. If the todo received in subscription data has id greater than the id 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}>
<FlatList
data={data.todos}
renderItem={({item}) => <TodoItem item={item} isPublic={isPublic}/>}
keyExtractor={(item) => item.id.toString()}
/>
<LoadOlder
isPublic={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}>
<FlatList
data={data.todos}
renderItem={({item}) => <TodoItem item={item} isPublic={isPublic}/>}
keyExtractor={(item) => item.id.toString()}
/>
<LoadOlder
isPublic={isPublic}
styles={styles}
/>
</ScrollView>
</View>

Awesome! You are now detecting new todo updates from the backend.

Now lets make this button functional.

Did you find this page helpful?
Start with GraphQL on Hasura for Free
  • ArrowBuild apps and APIs 10x faster
  • ArrowBuilt-in authorization and caching
  • Arrow8x more performant than hand-rolled APIs
Promo
footer illustration
Brand logo
© 2024 Hasura Inc. All rights reserved
Github
Titter
Discord
Facebook
Instagram
Youtube
Linkedin
graphql-handbook