DEV Community 👩‍💻👨‍💻

Paul Bennett
Paul Bennett

Posted on

Stop using multiple states for status

When it comes to fetching API data in React using fetch there can be ways to update the user or run conditional code. This can generally mean using a selection of different states. Which can potentially get messy and complicated.

You could have something like this:

const [data, setData] = useStatus([])
const [success, setSuccess] = useState('')
const [loading, setLoading] = useState('')
const [rejected, setRejected] = useState('')
const [error, setError] = useState('')
Enter fullscreen mode Exit fullscreen mode

Which in turn could be like the following:

useEffect(() => {

    setLoading('loading') // state 1

    fetch('http://some-api-url')
    .then(response => {
        setData(response)
        setSuccess('success') // state 2
    })
    .catch(err => {
        setError(err)
        setRejected('rejected') // state 3
    })

}, [])
Enter fullscreen mode Exit fullscreen mode

With the above we have three states to manage and keep an eye on. When it comes to using this conditionally it's going to be a pain in the ass. Something like this.

if (success === 'success') {
    //do something
} else if ( loading === 'loading' ) {
    // do something
} else if (rejected === 'rejected') {
    // do something
}
Enter fullscreen mode Exit fullscreen mode

Now wouldn't it be easier to use a status state instead of worrying about 3 other states. We can include something like a const [status, setStatus] = useStatus('idle') and remove all the other states apart from the setData and setError we need the error state so we can handle the displaying of error messages.

So now we have the following which is going to be much cleaner and easier to manage.

const [data, setData] = useStatus([])
const [error, setError] = useState('')
const [status, setStatus] = useState('idle')

useEffect(() => {

    setStatus('loading')

    fetch('http://some-api-url')
    .then(response => {
        setData(response)
        setStatus('success')
    })
    .catch(err => {
        setError(err)
        setStatus('rejected')
    })

}, [])

if (status === 'success') {
    // do something
} else if ( status === 'loading' ) {
    // do something
} else if (status === 'rejected') {
    // do something
}
Enter fullscreen mode Exit fullscreen mode

For me this is much a cleaner way of doing things, I know it's not that much different from using multiple states. However, we only have one state to deal with instead of three.

I got inspired to do things this way by Kent C Dodds. More information here

Top comments (0)

Need a better mental model for async/await?

Check out this classic DEV post on the subject.

⭐️🎀 JavaScript Visualized: Promises & Async/Await

async await