Today I am doing a code review of the meditation app @DoableDanny is working on. He graciously shared the source code with me.

Jump into the the 🧵to learn the #1 thing I teach junior devs at work about the React useState hook...

#100DaysOfCode D127
The app is built with React Native and well put together. If a junior dev sent this to me at work I would not be upset (though perhaps a bit surprised 😅).
In this review I'll focus on one particular area for improvement: useState hooks and more specifically using custom setters for complex state.

The app doesn't use a state manangement library like redux. Instead the global state is passed down from app.js
While redux gives you a consistent pattern for managing state and allows you to easily access global state from anywhere in the app, that same ease of access can make it hard to know from where state is being change. The same is true here. Let's look at an example!
As you can see in the gif, meditations is defined in App.js and passed to various components along with setMeditations. As a result, we have no idea here how the meditations may be modified. That logic is spread throughout those components so we'll have to dig through them.
Let's start with the HomeScreen:
Meditations are loaded from local storage here and state is set accordingly. That could probably be done in App.js
Next is the SettingsScreen:
Here setMeditations is used to delete progress and to delete stars.
The StatsScreen only loads the meditation from local storage again.

The TimerScreen updates the completion time for a meditation and unlocks the next meditation.
So what are the issues with this architecture?

- hard to trace changes
- multiple components know about loading from and saving to local storage
- components modifying meditations need to be aware of low level details (property names, first one is never locked, etc.)
Now let's look at how this could be improved: let's introduce a custom hook useMeditations which only exposes specific setters. It encapsulates the local storage feature and it's immediately clear what changes to the meditations are possible.
Using this in App.js it's now much more clear what changes can be mande on which screen. The components themselves can use the much simpler API these setters offer and don't need to concern themselves with localStorage.
This approach can be applied in many situations.

In this case you could even take it a step further and extract a generic useStoredState hook that handles the localStorage for all pieces of state. This hook would in turn be used by other custom hooks like useMeditations.
Let's wrap up. If you have a complex piece of state (not just a boolean, string or number) that you're updating in various places: put it in a custom hook and only expose simple setters to keep the complexity out of your components.
Like I said up front, I would absolutely expect to teach this type of stuff to a junior dev on their first job, so go get that job @DoableDanny ! You should be applying to jobs now if you aren't already. You can always keep learning more while you're looking.
Everyone else: If you're still here, I hope you got something out of this thread too. Please share it and if you'd like me to review some of your own code, please get in touch. It's free and I don't bite 😜
You can follow @simonpweller.
Tip: mention @twtextapp on a Twitter thread with the keyword “unroll” to get a link to it.

Latest Threads Unrolled: