Challenges

SWR

Error Handling

So far, we haven't look at error handling at all. Now it's time to take care of it.

Q: Try to create an empty todo item. What's your experience?
authenticating...

Here we are trying to capture errors thrown in the server. So, we have to run our API call inside a try-catch block.

Here's how the addTodo function looks like with that. Apply these changes:

const addTodo = async (todoName) => {
    // Add fake item and re-render the UI
    const fakeItem = {
        id: Math.random(),
        name: todoName,
        clientOnly: true
    }
    mutate('/api/todos', [...data, fakeItem], false)
    setListKey(Math.random())

    try {
        // Add the todo Item
        const addRes = await fetch('/api/todo', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({name: todoName})
        })

        if (!addRes.ok) {
            const {error} = await addRes.json()
            throw new Error(error.message);
        }

        // get the newly add to do
        const newTodo = await addRes.json();

        // replace above with the fake todo item
        mutate('/api/todos', (existingData) => {
            const newData = []
            for (const item of existingData) {
                if (item.id === fakeItem.id) {
                    newData.push(newTodo)
                    continue
                }
                newData.push(item)
            }
            
            return newData
        }, false)
    } catch(err) {
        // add the error message
        mutate('/api/todos', (existingData) => {
            const newData = []
            for (const item of existingData) {
                if (item.id === fakeItem.id) {
                    newData.push({
                        id: fakeItem.id,
                        errorMessage: err.message
                    })
                    continue
                }
                newData.push(item)
            }
            
            return newData
        }, false)
    }
}

(Here's the modified version of the components/Todos.js file.)

Have your attention to the catch block. In this case, we add the errorMessage field to the fake todo item. Then the components/TodoList.js can render it correctly.

mutate('/api/todos', (existingData) => {
    const newData = []
    for (const item of existingData) {
        if (item.id === fakeItem.id) {
            newData.push({
                id: fakeItem.id,
                errorMessage: err.message
            })
            continue
        }
        newData.push(item)
    }
    
    return newData
}, false)

Now let's do the same experiment as before:

Q: Try to create an empty todo item. What's your experience?
authenticating...

Here we have only handle errors when adding a todo item. That's something happening outside of SWR. But there could be errors when fetching data as well. You can check the error field when you invoke useSWR and change your UI accordingly.

const {data, error} = useSWR('/api/todos', jsonFetcher)