Recoil example with code, diagrams, and images.

A few days ago I’ve traveled to one of the neighboring cities called Rivne to move from my condo and live in a house for a few weeks to spend summertime enjoying the weather, nature, and some barbecue.

One evening I was sitting in the yard and checking the Medium feed and found an article about a new state management library called Recoil.

I took a quick look at it and became curious to find some simple code examples to help me understand how do you make things done using this library.

If you are like me wondering what is Recoil and want to see what is it capable of and how to manage your application state using it then this is the right article for you!

I did my best to cover this topic by creating a chat application using Recoil and I’m ready to share my experience using code, words, and images that I’ve prepared for you to better explain main concepts and ideas.

The structure of this article:

  • Chat app presentation with code examples
  • Fundamental Recoil building blocks
  • Recoil compared to Redux
  • Miscellaneous information about Recoil

I’m incredibly curious to see how to manage an app’s state using Recoil, what advantages does it have compared to alternative tools on the market and make myself acquainted with a new technology that seems to be promising.

With that said I invite you to join me today in creating the chat app using Recoil library and finding out the pros and cons of this tool.

You can find the complete code in my Github repository that contains Recoil Chat App.

Chat app presentation with code examples

Nowadays there are lots of chat apps that we use every day: Messenger, WhatsApp, Telegram.

In my country, there is a Viber chat app that is wildly popular and probably you’ve even heard about it, especially if you are from Ukraine or Poland.

Almost everyone knows how the basic chat app should work so I decided that the chat app should serve well as an example.

At first, I was thinking about creating a classic to-do list app but decided to improve my creativity a bit and make a small step toward thinking of something different from it. Here is how the idea of creating the chat app appeared in the first place.

For me, It is much easier to follow the code logic when you know what the ending result should be.

Here is what the app looks like:

Recoil chat app demo

Below I am leaving a few code snippets where I use Recoil to manage state for the application so you can become familiar with this technology.

That’s one of the main reasons why you landed on this post in the first place, isn’t it?

I suggest you not to focus too much on these examples, they are useful to make you acquainted with how the application state is managed using Recoil.

In the next sections of the article, we will take a closer look at Recoil components and utils.

Let’s start with the message input field as this is the most rudimentary component of the chat application in my opinion. Here is how it looks like:

import React from 'react'
import classNames from 'classnames'
import { useRecoilState } from 'recoil'

import { newChatMessageState } from '../recoil/atoms'
import { useSendMessage } from '../hooks'
import './styles.scss'

export default ({ className }) => {
  const [newMessage, setNewMessageText] = useRecoilState(newChatMessageState)
  const sendMessage = useSendMessage()

  const handleInput = (e) => setNewMessageText(e.target.value)

  const handleKeyPress = (e) => {
    if (e.which !== 13) {
      return
    }

    sendMessage()
  }

  return (
    <textarea
      className={classNames('ChatInput', className)}
      value={newMessage}
      onKeyPress={handleKeyPress}
      onChange={handleInput}
    />
  )
}
// hooks.js

import { useRecoilState } from 'recoil'

import { newChatMessageState, chatMessagesState } from '../recoil/atoms'

export const useSendMessage = () => {
  const [newMessage, setNewMessage] = useRecoilState(newChatMessageState)
  const [messages, setMessages] = useRecoilState(chatMessagesState)

  return () => {
    if (!newMessage) {
      return
    }

    setMessages([...messages, newMessage])
    setNewMessage('')
  }
}
// atoms.js

import { atom } from 'recoil'

export const chatMessagesState = atom({
  key: 'chatMessagesState',
  default: [],
})

export const newChatMessageState = atom({
  key: 'newChatMessageState',
  default: '',
})

Let’s describe in a few words what have we achieved with these lines of code:

  • I used useRecoilState and the related newChatMessageState atom to get the value of the particular piece of state and the setter function for this value to be able to change it as we type in the textarea.
  • I created a separate useSendMessage hook that helps to send a message. The reason why this is a separate hook is that it is used in chat-send-message component as well.
  • In useSendMessage I use useRecoilState again to receive the new message that is typed in the textarea and the setter be able to reset the textarea value after the message is sent.
  • Also in useSendMessage I added one more useRecoilState call to get the value of the existing messages and a setter to be able to add a new message to the already existing ones.

The main elements used to manage the state that you must have already discovered are useRecoilState and atom.

Here is a small diagram that shows how these elements are related to each other:

Atom/useReoilState diagram

If you want to check the complete code of the chat app you can find it in my Github repository.

Fundamental Recoil building blocks

Most of these elements you can see in use in the chat app. After the table, I will share code snippets for you to see how RecoilRoot and useRecoilValue are used.

And now let’s take a look at fundamental Recoil components and helper functions:

RecoilRootTo make Recoil work you will need to wrap your application with RecoilRoot element.

https://recoiljs.org/docs/api-reference/core/RecoilRoot/#example
atomAtom is a single piece of state. Something like newChatMessageState or chatMessagesState in our chat application.

https://github.com/Acousticdesk/recoil-chat/blob/master/src/components/chat/recoil/atoms.js

https://recoiljs.org/docs/basic-tutorial/atoms/
selectorWhen you need to calculate some value from multiple atoms (multiple pieces of state) use selector.

https://recoiljs.org/docs/basic-tutorial/selectors
useRecoilStateAllows you to access an atom value and setter for this value within a component.

https://recoiljs.org/docs/api-reference/core/useRecoilState/
useRecoilValueVery similar to useRecoilState. Returns a value, but not a setter.

https://recoiljs.org/docs/api-reference/core/useRecoilValue/
// index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { RecoilRoot } from 'recoil'

import App from './App'

import './styles/global.scss'

ReactDOM.render(
  <React.StrictMode>
    <RecoilRoot>
      <App />
    </RecoilRoot>
  </React.StrictMode>,
  document.getElementById('root')
)
// chat-messages/index.js

import React from 'react'
import { useRecoilValue } from 'recoil'

import ChatMessage from '../chat-message'
import { chatMessagesState } from '../recoil/atoms'
import './styles.scss'

export default () => {
  const messages = useRecoilValue(chatMessagesState)

  return (
    <div className="ChatMessages">
      {messages.map((message, index) => <ChatMessage key={`${message}_${index}`}>{message}</ChatMessage>)}
    </div>
  )
}

Recoil compared to Redux

I remember when 3 years ago I’ve been interviewed for a front-end position in a local company that deals with their own product that helps to edit PDF documents and the day before I had been checking all the Dan Abramov’s video tutorials on https://egghead.io/ as Redux was one of the main requirement for this role.

I was really excited by the Redux way of handling state changes and I still enjoy the developer experience it provides. Things like time-travel debugging, immutable state manipulations, a variety of compatible components, and the great community are just astonishing.

I’ve been using Redux for approximately 2 years now and I am incredibly happy with it. It has a few weaknesses like a necessity to put boilerplate code into your codebase and to include 3rd party libraries to handle async state changes, but this is my favorite state management library so far, though I think it may change when Recoil becomes a production-ready tool, we will see.

Let’s see how Recoil can be compared to Redux in my opinion:

ReduxRecoil
Time-travel debugging✔️✔️
Reactish way of dealing with stateno✔️
Async state changes out of the boxno✔️
A necessity to add boilerplate to the codebase✔️no
State persistence✔️✔️

A few links that may be useful to know more about Recoil:

Miscellaneous information about Recoil

While looking for the information about Recoil I’ve built a list that includes a bunch of random facts about Recoil that lives in one of my Notion pages.

I decided that I can leave all these facts here in this post so you can check them too.

Here it is:

Conclusion

There you have it! We’ve taken a look at chat app built using Recoil, discussed fundamental building blocks of Recoil, compared it to Redux, and collected a few random, but informative, in my opinion, facts about this great state management tool.

If you already tried to implement some app using Recoil that’s great! If you haven’t, then try doing it!

As David Thomas and Andrew Hunt explain in their book Pragmatic Programmer it is incredibly important to always try new things and technologies and to wrap your head around the new concepts to make yourself a better developer.

If you’ve enjoyed the article then you might check my previous ones:

If you would like to help me to become a better writer and help me to develop letconst to be an incredible tech blog then consider sending your feedback about this article to letconstportal@gmail.com

See you in the next articles!

Andrii