Im trying to develop a dynamic todoList.
I have two components TodoList, and Todo. TodoList fetches with useSWR the data from Mongo and puts the data in a div depending if they’re completed or not.
Todo component has a button to mark if the task its completed or not. When you click the input check it changes automatically on mongo.
Now I want that these change is reflected in the list too. For example, if a task its not completed it appears in todos. enter image description here
When I check the input in DB its marked as completed, but It still appears as not completed: enter image description here
TodoList.tsx
import React, { useState } from 'react'; import useSWR from 'swr'; import axios from 'axios'; import Todo from './Todo'; const fetcher = (url: string) => axios.get(url).then(res => res.data) export default function TodoList() { const { data, error } = useSWR('/api/v1/todos-all', fetcher) if (error) return <div>failed to load</div>; if (!data) return <div>loading...</div>; return ( <div> <div> <h1>To Do</h1> { data.todos.map((todo: any) => !todo.completed ? (<Todo key={todo._id} id={todo._id} title={todo.title} completed={todo.completed}/>) : (<></>)) } </div> <div> <h1>Completed</h1> { data.todos.map((todo: any) => todo.completed ? (<Todo key={todo._id} id={todo._id} title={todo.title} completed={todo.completed}/>) : (<></>)) } </div> </div> ) }
Todo.tsx
import React, { useState } from 'react'; import styled from 'styled-components'; import axios from 'axios'; interface ITodo { title: string; id: string; completed: boolean; } const TodoSyle = styled.div` background-color: #fff; padding: 20px; margin: 10px; border: 1px solid #eeeeee; border-radius: 10px; `; export default function Todo({title, id, completed}: ITodo) { const [checked, setChecked]= useState(completed) const handleClick = () => { setChecked(!checked) axios.put(`/api/v1/todo/${id}`, {"completed": `${!completed}`}) } console.log(id) return ( <TodoSyle> {title} <input type="checkbox" checked={checked} onChange={handleClick}/> </TodoSyle> ) }
Until you refresh the pag., which fetches the data again from db and it works. Is there a way to make rerender the app when the check button is clicked? Or there is a beeter approach to these problem?
Thanks
Advertisement
Answer
useSWR
won’t automatically refetch (revalidate) data by default, the cache will still be having the old data.
You can either enable automatic refetch using the refreshInterval
option.
const { data, error } = useSWR('/api/v1/todos-all', fetcher, { refreshInterval: 1000 });
Or explicitly update the data in cache yourself using a mutation after the PUT request to the API.
axios.put(`/api/v1/todo/${id}`, {"completed": `${!completed}`}) .then(() => { mutate() })