如何重新渲染组件以在Next.JS中显示新数据而无需重新加载页面?

waxmsbnn  于 2023-08-04  发布在  其他
关注(0)|答案(1)|浏览(169)

我正在使用Next.JSPrismaTypescriptPostgreSQL创建一个Todo-App,所有数据都是使用API文件夹获取的,该文件夹使用Prisma与数据库进行交互,对于Task表的CRUD操作,我只调用端点http:3000/api/tasks。任务由一个名为To-dos的组件渲染,该组件使用useEffect获取任务。
一切看起来都很好,但是当任何CRUD操作发生时,客户端中显示的数据不会更新,我需要重新加载页面,强制重新呈现组件以显示新数据。
如何解决此问题?

Todos.tsx

export default function Todos({ attribute, value, title, limit, addBtn }: arguments) {
  const [data, setData] = useState<Item[]>([]);

  //fetching data
  useEffect(() => {
    const fetchData = async () => {
      const response: any = await obtenerTasks({ attribute, value, limit });
      setData(response.response);
    };

    fetchData();
  }, []);

  return (
    <div>
      <div>
        <h1>{title}</h1>
        <div className='todos_container'>
          {
            data.map((item) => (
              <Task
                key={item.id}
                id={item.id}
                title={item.title}
                description={item.description}
                createdAt={item.createdAt}
                category={item.category}
                completed={item.completed}
                priority={item.priority}
                dueDate={item.dueDate}
              />
            ))
          }
        </div>
      </div>
      {addBtn && (
        <div className='todo_showMore'>
          <Link href={`/task/${attribute}?value=${value}`}>
            <p>ver mas</p>
          </Link>
        </div>
      )}
    </div>
  );
}

字符串

lib/task/API_task.ts

//get tasks
const obtenerTasks = async ({ attribute, value, limit }: TaskProps): Promise<any> => {
  try {
    let url: string = `http://localhost:3000/api/tasks?attribute=${attribute}&value=${value}`;
    if (limit) url += `&limit=${limit}`;
    const response = await axios.get(url);
    return { response: response.data, status: response.status }
  } catch (error) {
    throw new Error(String(error));
  }
};

//create task
const crearTask = async (task: Task): Promise<any> => {
  try {
    const url: string = "http://localhost:3000/api/tasks";
    const response = await axios.post(url, task);
    return { response: response.data, status: response.status }
  } catch (error) {
    throw new Error(String(error));
  }
};

//update task
const actualizarTask = async (task: Task): Promise<any> => {
  try {
    const url: string = `http://localhost:3000/api/tasks?id=${task.id}`;
    const response = await axios.put(url, task);
    return { response: response.data, status: response.status }
  } catch (error) {
    throw new Error(String(error));
  }
};

//delete taks
const eliminarTask = async (id: number): Promise<any> => {
  try {
    const url: string = `http://localhost:3000/api/tasks?id=${id}`;
    const response = await axios.delete(url);
    return { response: response.data, status: response.status }
  } catch (error) {
    throw new Error(String(error));
  }
};

首页.tsx

<div className="container_todos">
  <Todos attribute={"completed"} value={"false"} title={"Pendiente"} limit={3} addBtn={true} />
  <Todos attribute={"completed"} value={"true"} title={"Completado"} limit={3} addBtn={true} />
  <Todos attribute={"priority"} value={"true"} title={"Prioridad"} limit={3} addBtn={true} />
</div>

/API/task/route.tsPrisma与DB的交互

import prisma from '../../../../prisma/client/index';
import { NextResponse } from 'next/server';

//objeto todo con todos sus atributos
type Todo = {
  title: string,
  description?: string,
  category?: string,
  createdAt?: string,
  dueDate?: string,
  priority?: boolean,
  completed?: boolean,
}

//metodo GET que obtiene los Task que se filtran en base a sus atributos
export async function GET(request: Request) {
  try {
    const { searchParams } = new URL(request.url); //obtener parametros url
    const attribute = searchParams.get('attribute'); //obtener el atributo de la URL a buscar
    const value = searchParams.get('value'); //obtener el valor del atributo
    const limit = searchParams.get('limit'); //obtener el valor del atributo
    let isTrue = (value == "true") ? true : false; //variable auxiliar para consultar clausula
    let whereClause; //inicializacion de clausula
    let todos;

    //clausula de consulta a la base de datos
    if(attribute && value) {
       whereClause = { [attribute as string]: value };
    }

    //obtener los Task completados o marcados como prioridad
    if(attribute == "completed" || attribute == "priority") {
      whereClause = { [attribute as string]: isTrue };
    }

    //query de consulta a la base de datos
    if (limit) {
      const parsedLimit = parseInt(limit, 10);
      if (!isNaN(parsedLimit)) {
        todos = await prisma.todo.findMany({
          where: whereClause,
          take: parsedLimit
        });
      } else {
        todos = await prisma.todo.findMany({
          where: whereClause
        });
      }
    } else {
      todos = await prisma.todo.findMany({
        where: whereClause
      });
    }

    return NextResponse.json(todos);
  } catch (error) {
    console.log(error);
    return NextResponse.json({ error: 'Internal server error' });
  }
}

//metodo POST que crea un nuevo task
export async function POST(request: Request) {
  try {
    const data:Todo = await request.json();
    const {title, description, category, createdAt, dueDate, priority, completed} = data;
    const todo = await prisma.todo.create({
      data: {
        title,
        description,
        category,
        createdAt,
        dueDate,
        priority,
        completed,
      },
    });  
    return NextResponse.json(todo);
  } catch (error) {
    console.log(error)
  }
}

export async function PUT(request: Request) {
  const { searchParams } = new URL(request.url);
  const id = searchParams.get('id');
  const data: Todo = await request.json();
  const { title, description, category, createdAt, dueDate, priority, completed } = data;

  try {
    if (id) {
      const updatedTodo = await prisma.todo.update({
        where: { id: parseInt(id) },
        data: {
          title,
          description,
          category,
          createdAt,
          dueDate,
          priority,
          completed,
        },
      });
      return NextResponse.json(updatedTodo);
    } else {
      console.log('Param "id" is not present at URL');
    }
  } catch (error) {
    console.log(error);
  }
}

export async function DELETE(request: Request) {
  const { searchParams } = new URL(request.url);
  const id = searchParams.get('id');

  try {
    await prisma.todo.delete({
      where: {id: parseInt(id as string) }
    });
    return NextResponse.json({ msg: `Todo ID ${id} deleted successfully` });
  } catch (error) {
    console.log(error);
  }
}


我尝试使用轮询间隔获取数据每5秒,但它的方式太expense,我只是希望数据更新没有realoding网页

z8dt9xmd

z8dt9xmd1#

如果状态或属性改变,则react组件重新呈现。
如果你使用的是useEffect,如果它的一个依赖项改变了,它的效果会重新运行。由于useEffect依赖数组为空,这意味着它的效果仅在组件首次呈现时运行。为了重新运行useEffect效果,您需要添加一个可能会更改的依赖项。即应用程序中data状态值。但是如果你将data添加到dependency数组中,这将导致无限循环,因为如果data状态值更改,它将导致重新渲染应用程序,并且由于useEffect将依赖于data状态,它的效果将无限地重新运行。下面的设置应该可以工作。

useEffect(() => {
     const fetchData = async () => {
       const response: any = await obtenerTasks({ attribute, value, limit });
       setData(response.response);
     };

     fetchData();
  // those are props values that used inside `obtenerTasks`
  // when those changes, this useeffect will rerun 
  }, [attribute, value, limit]);

字符串

相关问题