Skip to content
Advertisement

React rerender component on database change

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()
  })
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement