Interaction
We have a full CRUD, front-end and back-end, but we're missing a crucial thing: feedback.
There are three major ways we're going to add feedback to our application:
Loading spinners: when something needs some time, we need to display something
Animations: when things change, we should be able to see the change thanks to clear visual changes
Notifications: when a form is submit, we want to know. When an error is received, we want to know too
Let's begin with the first: loading spinners.
Slow Database Calls
We're going to need a few things:
Artificially slow down the calls to the database, to simulate network load
Decide when to show this spinner
First, we're going to create a function sleep
, which will wait a bit before resuming.
Here's the code for it:
I will not explain the syntax here; it's out of the scope of this exercise's theme, and not very interesting.
Once that's done, we can also create a function that chooses a random number
We can then combine the two to get a random pause time. The following pauses for a random time between a second and four
We can make a shortcut for this:
We will create a file, utils.js
, to store those little functions:
Notice, we are not using export default
. We are using "named exports". To import each of these functions, we'll need to import it by name.
For example:
However, the below:
...will not work, since we are not exporting a default
.
You can now import it sprinkle it everywhere you have a fetch
:
If you try the app now, you will see interactions take time (don't forget to remove those later!).
You could also use the developper's tools of Chrome or Firefox to throttle the connection, but this is sometimes faster and simpler to set up. It also doesn't depend on dev tools being open.
Loading State
That gives us occasion to display something while loadings occur.
To do this, we'd need to have a switch in state
for when things are loading and when they are not.
Here's how it is going to work:
An
isLoading
key instate
, set tofalse
Before beginning to load, this
isLoading
will be set totrue
When the loading finishes, set this
isLoading
key back tofalse
Here's an example of how every fetch
function should work from now on:
Recap:
set isLoading
to true -> then load -> then set isLoading
to false.
note: Why did we call this isLoading
and not loading
or load
or anything else? Because load
, for example, might be an action. loading
might look like the <Loading/>
component we might create later. However, isLoading
is the least ambiguous. always choose unambiguous variable names.
Let's first implement that in the getContactsList
method:
We can now reflect that in the render
function. If isLoading
is true, we will show "loading...". If not, we will show the list:
Later, we can replace this "loading" thing with a spinner, an animation, or whatever else makes sense.
Animations
One more thing: we want animations when things get added or removed.
We will use react-spring. Performance is very high, usage is (relatively) simple, and it is well documented.
go to front
, and:
The way you use this is thus:
It is, at first sight, very complex; however it's merely difficult to read. Here are the properties needed
items
: a list of something. In our case, it's going to becontacts_list
key
: a function that returns keys. In our case, it'll return the contact'sid
from
,enter
,leave
: styles for different stage of transition of the itemitem => style => <Element>
: a function that returns a React element.props
represents the style thatreact-spring
creates
In our case, it will look something like:
Refresh, test, when the list of contacts load, you can see them sliding in nicely! Delete one, see how it also works smoothly.
Notifications
If you're using react-native-web
, you should rely on native notifications (not described here), but on the web, we will have to make use in-app alerts (we also could use the native notification API of browsers, but we'd need to get user permissions).
At first sight, it's not too difficult to make our own. A notification is something that:
is absolutely positioned
is dismissed when "close" is clicked
disappears on its own after some time
But if we think about it a bit more, we uncover that:
we need animations for entry and exit
we need to stack messages if there are more than one
we need to add icons and styles
some messages might need buttons with specific interactions
we might want some messages to not disappear until a user dismisses them
we might want some messages to not disappear at all ("you are currently offline"...)
...
Fortunately, there are many read-made libraries. I like react-toastify, so this is what we'll use:
Install it. Move to front
, and
Then, import it in App.js
. We need to import three things:
<ToastContainer/>
, which will contain all our notifications. We need to use it once, in our main appthe toastify css file, so the styles can be applied. This also just needs to be imported once
the
toast
function, which creates a toast.
We can now call toast("a message")
anywhere we want. We can try this:
Refresh, you should see a "contacts loaded" message.
Note:
You have to apply the same to every other CRUD Method 1. createContact 2. updateContact 3. deleteContact 4. getContact
Once you're done, remove the error message from render
, as it is not needed there anymore.
react-toastify has a lot of customization options, so do check it out.
It uses its own animation system, so, of course, by using it, you're duplicating parts of what your css and react-spring
are doing, so if you want to keep your dependencies low and implement your own toast system, this codesandbox is a good starting point.
TODO
Display a loading spinner instead of a "loading..." text
Last updated