Handle real-time application notifications in Reactjs
Tags: javascript, react, webdev, tutorial
Published: 2022-04-20 11:34:43

Handle real-time application notifications in Reactjs
Notifications are used to draw a user's attention to a piece of specific information. Notifications are as versatile as they come, with different brands adopting notification mediums like messages, emails icons on the website or application. They are usually employed to engage users and retain website visitors. Other times, notifications are used internally to monitor application metrics and state.

## What we will be building

This post will discuss how to manage real-time app notifications in React.js. We will trigger and subscribe to notifications when events in our database occur. This doesn’t require a custom server.

**GitHub URL** 

https://github.com/Iheanacho-ai/appwrite--notifications-app

**Prerequisites**
To get the most out of this article, we require the following:

- A basic understanding of CSS, JavaScript, and React.js.
- Docker Desktop installed on our computer. Run the `docker -v` command to verify if you have docker desktop installed. If not, install it from [here](https://www.docker.com/products/docker-desktop/). 
- An [Appwrite](https://appwrite.io/) instance running on our computer. Check out the [documentation](https://appwrite.io/docs/installation#installWithDocker?utm_source=hackmamba&utm_medium=blog&utm_campaign=react-notifications) to create a local Appwrite instance. We will use Appwrite’s powerful real-time service handle application notifications.


## Setting up the React.js application

We navigate to our preferred directory to create a React.js application using this command:

```bash
    npx create-react-app <name of our app>
```
After creating our app, we change the directory to our project and start a local development server with:

```bash
    cd <name of our project>
    npm run start
```
To see the app, we go to https://localhost:3000


![React.js index page](https://paper-attachments.dropbox.com/s_D2E5BC9B38347E8D57CD4461AFFDE366C2A526B69F66F91BFA9637322C3A4BD9_1624279658117_React+app.PNG)



## Installing dependencies

**Installing Appwrite**
[Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=blog&utm_campaign=react-notifications) is an open-source, end-to-end, back-end server solution that allows developers to build applications faster. Appwrite provides ready-made tools and systems to build production ready applications.

We install the Appwrite React.js client-side SDK by running this terminal command.

```bash
    npm install appwrite
```

**Installing react-toastify**

[React-Toastify](https://openbase.com/js/react-toastify) is a react framework that allows us to create super customizable notification component.

We run these commands to install react-toastify.

```bash
    npm install --save react-toastify
    #or
    yarn add react-toastify
```

Creating a new Appwrite project

Running a local Appwrite instance gives us access to our console. We go to the local Appwrite instance on whatever port it is started on to create an account. Typically, this is on [localhost:80](http://localhost/) or as specified during Appwrite’s installation.

On the console, there is a **Create Project** button. We click on it to start a new project.
  
Our project dashboard appears once we have created the project. At the top of the page, there is a **settings** bar. Click it to access and copy the **Project ID** and **API Endpoint**. We will use these next.

In the `App.jsx` file, we create a new Appwrite instance using the project ID and endpoint.

```jsx
    import {Appwrite} from "appwrite";
    import {useEffect, useState } from "react";
    import './App.css';
    
    const App = () => {
    
        // Init our Web SDK
        const sdk = new Appwrite();
        sdk
        .setEndpoint('http://localhost/v1') // our API Endpoint
        .setProject(projectID) // our project ID
        ;
    
        return(
          <div>Hello World!</div>
        )
    }
    
    export default Home;
```
**Creating the database collection and attributes**

Go to our [Console](http://localhost/console). On the left side of our dashboard, click on Database. Clicking on the Database menu redirects us to a collection page.

We create a collection in our database tab by clicking on the **Add Collection** button. This action redirects us to a **Permissions** page.

At the **Collection level**, we want to assign **Read** and **Write Access** with **role:all** value. 


![Appwrite Collection level page](https://paper-attachments.dropbox.com/s_2159BF3A474A99191FE34C7AAFCC4D90DCDE0B381CEEF8564F73F3F95BFA6945_1648376544970_Screenshot+63.png)


On the right of our **Permissions** page, we copy our **Collection ID**, which we need to perform operations on documents in this collection.

Next, we go to our attributes tab to create the properties we want a document to have. 

We need a single string attribute of **message**.


![Appwrite attribute level page](https://paper-attachments.dropbox.com/s_2159BF3A474A99191FE34C7AAFCC4D90DCDE0B381CEEF8564F73F3F95BFA6945_1648376497943_Screenshot+61.png)

## Creating our Notification application.

Our notification application UI consists of three buttons, to create a document, update the document, and lastly, to delete the document.

We go to our `App.jsx` and create the buttons with:

```jsx
    import {Appwrite} from "appwrite";
    import './App.css';
    
    const App = () => {
      // Init our Web SDK
        const sdk = new Appwrite();
        sdk
        .setEndpoint('http://localhost/v1') // our API Endpoint
        .setProject(projectID) // our project ID
        ;
      return (
        <div className="App">
          <button type='button'>Create Document</button>
          <button type='button'>Update Document</button>
          <button type='button'>Delete Document</button>
        </div> 
      )
    }

```
## Handling database interactions

Appwrite only allows signed-in users to read or write to the database as a safety policy. However, Appwrite enables us to create an anonymous session to bypass this policy.

In our `index.js` file, we create our anonymous user session using Appwrite's `createAnonymousSession` method. We then specify with a `useEffect` hook that we want to call our `createAnonymousSession` once our app mounts.

```js
    //creating an anonymous Session
    const createAnonymousSession = async() => {
      try{
        await sdk.account.createAnonymousSession();
      }catch(err){
        console.log(err)
      }
        
    }
    useEffect(()=> {
      createAnonymousSession()
    }, [])
    
```

Next, using the React `useState` hook, we want to create two state variables, `theArray`, and `response`. 

- The `theArray` state variable holds the document ID number of every document we will create in our database.
- The `response` state variable contains the real-time notification payloads received from Appwrite.

 ```jsx

    const [theArray, setTheArray] = useState([]);
    const [response, setResponse] = useState('Welcome!');

```

**Subscribing to our collection events**

Our application displays a notification every time we create, update, or delete documents in our collection. We achieve this by subscribing to our collection to get a payload each time a database action occurs.

```jsx
    const sdk = new Appwrite();
      sdk
        .setEndpoint('http://localhost/v1') // Your Appwrite Endpoint
        .setProject(projectsID) // Your project ID
      ;
      async function createAnonymousSession(){
        try{
            await sdk.account.createAnonymousSession();
        }catch(err){
            console.log(err)
        }
        
      }
      useEffect(()=> {
        createAnonymousSession();
        if(sdk.account.get !== null){
          try {
            sdk.subscribe('collections.[collectionID].documents', response => {
              setResponse(`The Appwrite ${response.event} event was called`)
          
              
            });
            
          } catch (error) {
            console.log(error, 'error')
          }
        }
    
      }, [])
```
In the code block above, we do the following:

- Check if `sdk.account.get` is not null. This check ensures that we have an active user session running before subscribing to our collections channel.
- Use Appwrite's `subscribe` method, which receives the channel we want to subscribe to and a callback function as parameters. To understand more about the various channels we can subscribe to, check out Appwrite's docs.
- Updates the `response` state variable with the callback function's response. 

**Listing our documents**

In our `App.jsx` file, we create a `listDocuments` function to retrieve data from the database and populate the `theArray` array.

```jsx
    const listDocuments = async() => {
      try { 
        let response = await sdk.database.listDocuments(collectionID);
        response.documents.map(document => setTheArray(prevArray => [...prevArray, document.$id]) )
      
    } catch (error) {
        console.log(error);
      }
    }

```

We use Appwrite's `listDocuments` function to retrieve our data, which receives a collection ID parameter. This collection ID is the same ID we obtained from the Appwrite console’s Permissions Page. 

The `listDocuments` function pushes each of the newly created document's ID into `theArray` array.

**Creating new documents**

In our `App.jsx` file, we write our `createDocument` function to create default documents in our database. We use this to simulate an event trigger.

```jsx
    const createDocument = async () => {
      try{
        await sdk.database.createDocument(collectionID, "unique()", {
          "message": "Hello World!",
        });
       
        listDocuments()
        
      }catch(error){
        console.log(error)
      }
             
      }
```
The `createDocument` function above does the following:

- Use the Appwrite `createDocument()` method, the collection ID, and the document payload to create a new document.
- Calls the `listDocuments` function.
- Logs an error if creating the document fails.


## Deleting documents in the collection.

In our `App.jsx` file, we create a `deleteDocument` method to delete a document in our collection.

```jsx
    const deleteDocument = async () => {
      if (theArray.length > 0) {
        try {
          let documentID = theArray[theArray.length - 1]
          await sdk.database.deleteDocument(collectionID, documentID);
          listDocuments();
        } catch (error) {
          console.log(error)
          }  
        } else {
          alert('database is empty')
        }
    }
```

The `deleteDocument` function does the following:

- Checks if the `theArray` length is greater than zero. If it is, we want to store the last document ID in our array in a `documentID` variable. However, if `theArray` length is less than zero, we want to alert that the database is empty.
- Deletes the document using the Appwrite `deleteDocument()` method. This `deleteDocument` method receives a collection ID and the document ID parameter.
- Runs the `listDocuments` function.
- Logs an error if creating the document fails.

Here is what our `App.js` file looks like.

https://gist.github.com/Iheanacho-ai/c3d5edf96cb59b045f4d53376cc5b7fe


Next, we pass these functions to an `onClick` event listener on the buttons.

```jsx
    <div className="App">
      <button type='button' onClick={createDocument}>Create Document</button>
      <button type='button' onClick={deleteDocument}>Delete Document</button>
    </div>

```

## Creating our React-Toastify notifications

This section will discuss creating notifications in our application with the react-toastify library. 

To use react-toastify notifications in our app, we need to import the `ToastContainer` component, the `toast` instance, and its CSS styles in the `App.jsx` file. 

```jsx

    import { ToastContainer, toast } from 'react-toastify';
    import 'react-toastify/dist/ReactToastify.css';
```

Next, we specify the information we want our notification to display with this piece of code below.

```jsx
    const notify = (response) => {
      toast(response)
    };
    
    useEffect(() => {
      notify(response);
    }, [response]);
 
```   

We create a `notify` function in the code block above to call our `toast` function. This `toast` function receives our response variable as a parameter. The `response` data will be passed in the toast.

We then use the `useEffect` hook to run our `notify` function when our response parameter changes.

Finally, we then add the `ToastContainer` component to our project.

```jsx
    return (
      <div className="App">
        <button type='button' onClick={createDocument}>Create Document</button>
        <button type='button' onClick={deleteDocument}>Delete Document</button>
        <ToastContainer/>
      </div>
    );

```
Here is what our `App.jsx` file should look like.

https://gist.github.com/Iheanacho-ai/656f05b6e98ca1422633b112f85b37f8

Here is our notifications app.

    
![React notifications app with Appwrite](https://paper-attachments.dropbox.com/s_2159BF3A474A99191FE34C7AAFCC4D90DCDE0B381CEEF8564F73F3F95BFA6945_1648599408596_notifications-app.gif)


By clicking each button, we receive a notification of the action. This project simulates this on a single page, more complex applications would utilize this interaction across pages, devices or independent interfaces. 

## Conclusion

This article discussed using Appwrite’s realtime feature to subscribe to application events.

## Resources

Here are some resources that might be helpful:


- [Getting started with Appwrite for web](https://appwrite.io/docs/getting-started-for-web?utm_source=hackmamba&utm_medium=blog&utm_campaign=react-notifications)
- [react-toastify](https://openbase.com/js/react-toastify)
- [What is Appwrite and How to use it Efficiently.](https://appwrite.io/docs/getting-started-for-web[](url))