简体   繁体   English

在数据库更改时反应重新渲染组件

[英]React rerender component on database change

Im trying to develop a dynamic todoList.我正在尝试开发一个动态的待办事项列表。

I have two components TodoList, and Todo.我有两个组件 TodoList 和 Todo。 TodoList fetches with useSWR the data from Mongo and puts the data in a div depending if they're completed or not. TodoList 使用 useSWR 从 Mongo 获取数据,并根据它们是否完成将数据放入 div 中。

Todo component has a button to mark if the task its completed or not. Todo 组件有一个按钮来标记任务是否已完成。 When you click the input check it changes automatically on mongo.当您单击输入检查时,它会在 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 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 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.直到你刷新 pag.,它再次从 db 获取数据并且它工作。 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谢谢

useSWR won't automatically refetch (revalidate) data by default, the cache will still be having the old data.默认情况下, useSWR不会自动重新获取(重新验证)数据,缓存仍将具有旧数据。

You can either enable automatic refetch using the refreshInterval option.您可以使用refreshInterval选项启用自动重新获取。

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.或者在对 API 的 PUT 请求后使用突变显式更新缓存中的数据。

axios.put(`/api/v1/todo/${id}`, {"completed": `${!completed}`})
  .then(() => {
      mutate()
  })

I have never used useSWR hook before, but maybe it could help you.我以前从未使用useSWR钩子,但也许它可以帮助你。

You should move handleClick function to TodoList.tsx and use mutate to update client cache ( data )您应该将handleClick function 移动到TodoList.tsx并使用mutate更新客户端缓存( data

const { data, error, mutate } = useSWR('/api/v1/todos-all', fetcher);

...

const handleClick = (todo, value) => {
  axios.put(`/api/v1/todo/${todo._id}`, { completed: !value}).then(() => {
    todo.completed = value;
    mutate([...todos]);
  });
};

return
  ...
    {
      data.todos.map((todo: any) =>
        todo.completed ? (
          <Todo key={todo._id} todo={todo} onClick={handleClick} />
        ) : null
      );
    }

Todo.tsx Todo.tsx

...
<input
  type="checkbox"
  value={todo.checked}
  onChange={(e) => onClick(todo, e.target.checked)}
/>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM