In this article, we aim to present a use case on how to use React Hooks and Context API in order to show notifications globally. The example presented here creates a way to show error messages (namely API error messages) reported by feature components (our pages) when a request is performed. The approach presented here was inspired by the pattern extinction level event. In the end, we also explain how to easily test some of the components created. You can find the full code examples described in this blogpost in this codesandbox.

We have a folder structure similar to the following:

src/App.js is the entry point for our React application, similar to what is created with Create React App.

The src/components folder contains basic react components that range from Button to Modal, Header, Footer, etc (for such a simple project we didn't feel the need to split using something such as atomic design). The features folder contains the pages, that are smart components that handle network requests and the structure of the pages.

API requests, custom React Hooks and Providers created with Context API can be found in a common folder, as they can be shared through the components (namely, features).

OK, but what do we want exactly to do? a bottom-up approach to push errors and make them visible. Context seemed a good candidate to handle that.

Since we just need to show one error message at a time we can just save that message (string) and the status code in context. The functions to add and remove (clear) the error are also exposed in context through the provider.

We need to add our APIErrorProvider pretty much we add other providers such as Authentication provider or Material ui to our main App component.

Note that we also add APIErrorNotification component here which is the component that will render our popup notification with the error.

Using your own hook and avoid having to do useContext in every component

The useAPIError custom hook does not do anything fancy but makes the code more readable and avoids having to write too many lines. It exposes the addError and removeError functions and the error to used by APIErrorNotification .

Now we can use our custom hook in a feature page, such as the following example. Here we are doing a request to an API when the component mounts ( useEffect with no dependencies). If the request fails we call the addError method in our Provider and the context gets updated.

Once the context gets updated, the APIErrorNotification is notified that its value changed and rerenders. We can show a message in a paragraph (or markup, why not?), use a modal, a toast / snackbar or other. In this case, imagine that we have a modal component that just shows up when there's an error:

Note that the way to remove the error message is to submits the modal, which will update the context and trigger a rerender where modal will not show up.

We are going to use @testing-library/react in the following examples. It is really simple to use, and the whole idea is to test as a user which helps to identify the use cases and meet user acceptance criteria. There is also react-hooks-testing-library which might help to test our custom hooks.

From this example you can see that:

We can pass a custom error message or just use a mocked one;

We are extending the functions provided by @testing-library/react ( getByTestId , queryByTestId , etc) which means that we test addErrorSpy and removeErrorSpy usages properly.

In order to use it on a test we can do the following:

For example, if we add the data-testid attribute to the submit button on the APIErrorNotification component we can trigger it and confirm that removeErrorSpy was called when the button was pressed.

Note that we wanted to show how it is possible to test the functions of the provider. However, in this particular example we could just have tested that the modal was not visible anymore, e.g.

We hope this gave some ideas on how to use Context API and on how to test your use cases. Happy coding!