Creating flow using useState
Nolan Miller
Posted on July 20, 2024
Today it seemed that I’m not moving as quickly as I have the past few days.
I started work today on the card that most of the user interaction happens with. And since this is the part I care the most about, this is also taking the most time! I spent a good couple of hours fighting with the form, trying to implement an animation for the form labels. I did eventually get it, but after working on it for so long, I feel like I need a bit of a break.
Either way, I found a solution for the bigger picture flow of how the card works.
Why Do I Need Flow?
When I hit the “Start a new roast” button, there multiple screens that need to be passed through in one card. A form to get information about the coffee and beans being used and some of the parameters of the roast, the actual timer with the breakpoints for different steps, another form that takes in some of the after-roast details and a summary view that shows all of the details of the roast that have been calculated in the end.
I needed an elegant way of getting from one screen to the next, all within one component.
Implementing useState to Create Flow
I have three different states that control the rendering and the appearance of my Roaster
component.
Within my Home
component, I initialized a state that tracks wether or not the roaster is active, and then I conditionally render out my Roaster
component if it's active.
// Home.js
// .. imports
import { useState } from 'react'
function Home() {
const [roastActive, setRoastActive] = useState(false);
const newRoast = new Roast(Date.now());
const handleNewRoast = () => setRoastActive(true);
const closeRoaster = () => setRoastActive(false);
return !roastActive ?
(
<> {/* My Home component */}</>
)
:
(
<Roaster roast={newRoast} close={closeRoaster} />
)
}
When the Roaster component is active, I’ve thrown the closeRoaster
function down to it as a prop so that I can escape the window without having to navigate away from this page.
What’s going on in Roaster
then?
In the Roaster
component, I declared two more state variables that keep track of where the user is in the roasting flow. One of them tracks the view of the card and the other tracks the step within the actual roast.
Take a look:
// Roaster.js
// ... imports
import { useState } from 'react'
function Roaster() {
const [progress, setProgress] = useState("start-roast-form")
// start-roast-form > roast-active > finish-roast-form > roast-complete
const [roastStep, setRoastStep] = useState(1);
// steps are 1-5
As you can see from my comments, I’m using string values to move through the progress
state. This is to make it easier to work with as I jump up and down this file.
The roastStep
state is just integers, because they are actually labeled in the UI with numbers.
Then I created two little helper functions that move users through the stages an eventually closes the card with useEffect
once it's been set to 'inactive’ .
// Move through the different roaster states
const nextProgress = () => {
setProgress(progress === 'start-roast-form'
? 'roast-active'
: progress === 'roast-active'
? 'finish-roast-form'
: progress === 'finish-roast-form'
? 'roast-complete'
: progress === 'roast-complete'
? 'inactive'
: 'inactive'
)
}
// Control steps during the roasting
const nextStep = () => {
if (roastStep < 5) {
setRoastStep(roastStep + 1);
} else {
nextProgress();
}
}
// Trigger rerender of the Home Page component
useEffect(() => {
if (progress === 'inactive') {
close();
}
})
Then all that’s left is to do is to conditionally render out the pieces of the UI that I want to for the different states:
return progress === 'start-roast-form' ?
(
<></>
)
: progress === 'roast-active' ?
(
<></>
)
: progress === 'finish-roast-form' ?
(
<></>
)
: progress === 'roast-complete' ?
(
<></>
)
: <></>
}
Obviously, replacing the fragments here with the components that make up each of the views.
What Do We Get?
Check out the gif above for the general loop of the UI! I don’t have all of the UI written in yet, but you get a general idea of the flow.
The form opens, then you get to the roast page, where you progress through 5 steps (you can’t see me tapping the “Record step” button 5 times), and then we cycle through the next two pages before closing the card and re-rendering our home page!
One of these days, I’ll write those active state styling into the button…
Thanks for reading!
Check Out the Repo
If you want to keep up with the changes, fork and run locally, or even suggest code changes, here’s a link to the GitHub repo!
Posted on July 20, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.