简体   繁体   English

在 prop 更改时重新渲染组件

[英]Re-rendering a component on prop change

I am new in the react world and I need help.我是 React 世界的新手,我需要帮助。

I have a problem with re-rendering data in my Table component.我在我的 Table 组件中重新呈现数据时遇到问题。 When I create a new API call, where I create a new entry in my DB with Prisma, that new data is not re-rendered in the DataTableMaterial component.DataTableMaterial as a prop gets an array of elements from the DB (Prisma call in the getServerSideProps).当我创建一个新的 API 调用时,我使用 Prisma 在我的数据库中创建一个新条目,该新数据不会在 DataTableMaterial 组件中重新呈现。 getServerSideProps)。 My question is how do I re-render my table when I submit my form for adding new data to the DB?我的问题是,当我提交表单以向数据库添加新数据时,如何重新呈现我的表?

I'm using: Node: v16.9.1 npm: 8.0.0 prisma: 3.2.1 next: latest我正在使用:节点:v16.9.1 npm:8.0.0prisma:3.2.1 下一个:最新

My DataTableMaterial.js component我的 DataTableMaterial.js 组件

import React from "react";
import MaterialTable from "material-table";

import { forwardRef } from "react";

function DataTableMaterial({ data, tipPotvrde, tipPodrske }) {
  const tableIcons = {
    Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
    Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
    Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
    Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
    DetailPanel: forwardRef((props, ref) => (
      <ChevronRight {...props} ref={ref} />
    )),
    Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
    Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
    Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
    FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
    LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
    NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
    PreviousPage: forwardRef((props, ref) => (
      <ChevronLeft {...props} ref={ref} />
    )),
    ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
    Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
    SortArrow: forwardRef((props, ref) => (
      <ArrowDownward {...props} ref={ref} />
    )),
    ThirdStateCheck: forwardRef((props, ref) => (
      <Remove {...props} ref={ref} />
    )),
    ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />),
  };

  return (
    <div>
      {console.log(data)}
      <MaterialTable
        icons={tableIcons}
        columns={[
          {
            title: "Datum unosa",
            field: "datumUnosa",
            render: (rowData) =>
              new Date(rowData.datumUnosa).toLocaleDateString(),
          },
          { title: "Mesec", field: "mesec" },
          { title: "Grupa", field: "grupa" },
          { title: "Opis/Model/Svrha", field: "pm" },
          { title: "PM", field: "opis" },
          {
            title: "Tip podrske",
            field: "tipPodrske_id",
            render: (rowData) => getTypeForPodrskaId(rowData.tipPodrske_id),
          },
          { title: "Iznos", field: "iznos" },
          { title: "Planirana kolicina/vrednost", field: "planKolVred" },
          { title: "Planirana podrska", field: "planPodrska", type: "numeric" },
          {
            title: "Potvrdjena podrska",
            field: "potvrPodrska",
            type: "numeric",
          },
          {
            title: "Potvrdjena",
            field: "potvr",
            render: (rowData) => (rowData.potvr ? "Da" : "Ne"),
          },
          {
            title: "Tip potvrde",
            field: "tipPotvrde_id",
            render: (rowData) => getTypeForPotvrdaId(rowData.tipPotvrde_id),
          },
          {
            title: "Fakturisano",
            field: "fakturisano",
            render: (rowData) => (rowData.fakturisano ? "Da" : "Ne"),
          },
          {
            title: "Datum fakturisanja",
            field: "datumFakt",
            render: (rowData) =>
              new Date(rowData.datumFakt).toLocaleDateString(),
          },
          { title: "Broj fakture", field: "brFakture" },
        ]}
        data={data}
        title="Lista"
        options={{
          exportButton: true,
          filtering: true
        }}
      />
    </div>
  );
}

export default DataTableMaterial;

This is my index.js page这是我的 index.js 页面

import Head from "next/head";
import Dropdown from "../components/Dropdown";
import InputForm from "../components/InputForm";
import { PrismaClient } from "@prisma/client";
import { useState, useEffect } from "react";
import DataTableMaterial from "../components/DataTableMaterial";

export default function Home({ inputs, tipPodrske, tipPotvrde }) {
  const [newInputs, setNewInputs] = useState(inputs);

  useEffect(() => {
    setNewInputs([...inputs]);
  }, [inputs]);

  return (
    <div>
      <Head>
        <title>Backrebate</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Dropdown />
      <InputForm tipPotvrde={tipPotvrde} tipPodrske={tipPodrske} />
      <DataTableMaterial
        data={newInputs}
        tipPotvrde={tipPotvrde}
        tipPodrske={tipPodrske}
      />
    </div>
  );
}

export async function getServerSideProps() {
  const prisma = new PrismaClient();
  const inputs = await prisma.input.findMany();
  const tipPotvrde = await prisma.tipPotvrde.findMany();
  const tipPodrske = await prisma.tipPodrske.findMany();
  return {
    props: {
      inputs,
      tipPodrske,
      tipPotvrde,
    },
  };
}

This is my API call from the submitFormHandler这是我从 submitFormHandler 调用的 API

const submitHandler = async (e) => {
    e.preventDefault();

    try {
      console.log(formData);

      await fetch("/api/inputs", {
        method: "POST",
        body: JSON.stringify(formData),
      });
      handleClose();
    } catch (error) {
      console.error(error);
    }
  };

From api/inputs来自 api/输入

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default async (req, res) => {
  try {
    const data = JSON.parse(req.body);
    const createdInput = await prisma.input.create({
      data,
    });
    res.json(createdInput);
  } catch (error) {
    console.error("Form input not valid(Fill all fileds!)");
    console.error(error);
  }
};

InputForm.js输入表单.js

import groupsJSON from "../data/groups.json";
import { Modal } from "react-bootstrap";
import { useState } from "react";

function InputForm(props) {
  const months = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
  ];

  const [formData, setFormData] = useState({
    datumUnosa: null,
    mesec: months[0],
    pm: null,
    grupa: groupsJSON.groups[0],
    opis: null,
    dobavljac: null,
    tipPodrske: {
      connect: {
        id: props.tipPodrske[0].id,
      },
    },
    iznos: null,
    planKolVred: null,
    planPodrska: null,
    potvrPodrska: null,
    tipPotvrde: {
      connect: {
        id: props.tipPotvrde[0].id,
      },
    },
    potvr: true,
    fakturisano: true,
    datumFakt: null,
    brFakture: null,
  });

  const [show, setShow] = useState(false);

  const handleClose = () => setShow(false);
  const handleShow = () => setShow(true);

  const str2bool = (value) => {
    if (value && typeof value === "string") {
      if (value.toLowerCase() === "true") return true;
      if (value.toLowerCase() === "false") return false;
    }
    return value;
  };

  const submitHandler = async (e) => {
    e.preventDefault();

    try {
      console.log(formData);

      await fetch("/api/inputs", {
        method: "POST",
        body: JSON.stringify(formData),
      });
      handleClose();
    } catch (error) {
      console.error(error);
    }
  };

  return (
    <>
      <button
        onClick={handleShow}
        className="bg-blue-900 text-white px-7 py-2 rounded-md ml-4 mt-4"
      >
        Create new
      </button>

      <Modal show={show} onHide={handleClose} size="lg">
        <Modal.Header closeButton>New input</Modal.Header>
        <Modal.Body>
          <div className="relative">
            <form action="#" method="POST" onSubmit={submitHandler}>
              <div className="shadow overflow-hidden sm:rounded-md">
                <div className="px-4 py-5 bg-white sm:p-6">
                  <div className="grid grid-cols-6 gap-6 items-center">
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="date"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Datum unosa
                      </label>
                      <input
                        type="date"
                        name="date"
                        id="date"
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            datumUnosa: new Date(e.target.value).getTime(),
                          })
                        }
                        className="outline-none mt-1 h-10 focus:ring-indigo-500 bg-gray-50 focus:border-indigo-500 block w-full shadow-md sm:text-sm border-gray-300 rounded-md"
                      />
                    </div>

                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="pm"
                        className="block text-sm font-medium text-gray-700"
                      >
                        PM
                      </label>
                      <input
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            pm: e.target.value,
                          })
                        }
                        type="text"
                        name="pm"
                        id="pm"
                        className="outline-none mt-1 h-10 pl-3 focus:ring-indigo-500 bg-gray-50 focus:border-indigo-500 block w-full shadow-md sm:text-sm border-gray-300 rounded-md"
                      />
                    </div>

                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="mesec"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Mesec
                      </label>
                      <select
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            mesec: e.target.value,
                          })
                        }
                        id="mesec"
                        name="mesec"
                        className="outline-none mt-1 block w-full py-2 px-3  bg-gray-50 border-gray-300 rounded-md shadow-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                      >
                        {months.map((month) => (
                          <option>{month}</option>
                        ))}
                      </select>
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="grupa"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Grupa
                      </label>
                      <select
                        id="grupa"
                        name="grupa"
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            grupa: e.target.value,
                          })
                        }
                        className="outline-none mt-1 block w-full py-2 px-3  bg-gray-50 border-gray-300 rounded-md shadow-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                      >
                        {groupsJSON.groups.map((group, i) => (
                          <option value={group} key={i}>
                            {group}
                          </option>
                        ))}
                      </select>
                    </div>

                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="opis"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Opis/Model/Svrha
                      </label>
                      <textarea
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            opis: e.target.value,
                          })
                        }
                        type="text"
                        name="opis"
                        id="pm"
                        className="outline-none pl-3 pt-1 mt-1 h-20 bg-gray-50 block w-full shadow-md sm:text-sm border-gray-300 rounded-md"
                      />
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="dobavljac"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Dobavljac
                      </label>
                      <input
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            dobavljac: e.target.value,
                          })
                        }
                        type="text"
                        name="dobavljac"
                        id="dobavljac"
                        className=" pl-3 outline-none mt-1 h-10 bg-gray-50 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-md sm:text-sm border-gray-300 rounded-md"
                      />
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="tipPodrske"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Tip podrske
                      </label>
                      <select
                        onChange={(e) => {
                          setFormData({
                            ...formData,
                            tipPodrske: {
                              connect: {
                                id: parseInt(e.target.value),
                              },
                            },
                          });
                          console.log(e.target.value);
                        }}
                        id="tipPodrske"
                        name="tipPodrske"
                        className="outline-none mt-1 block w-full py-2 px-3  bg-gray-50 border-gray-300 rounded-md shadow-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                      >
                        {props.tipPodrske.map((tip) => (
                          <option value={tip.id} key={tip.id}>
                            {tip.naziv}
                          </option>
                        ))}
                      </select>
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="iznos"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Iznos (%%, RSD po kom, RSD total...)
                      </label>
                      <div class="flex flex-wrap overflow-hidden bg-transparent drop-shadow-md">
                        <input
                          onChange={(e) => {
                            setFormData({
                              ...formData,
                              iznos: e.target.value,
                            });
                          }}
                          type="text"
                          name="iznos"
                          id="iznos"
                          className=" pl-3 outline-none mt-1 h-10 bg-gray-50 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-md sm:text-sm border-gray-300 rounded-md"
                        />
                      </div>
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="planiranaKolicina"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Planirana kolicina/vrednost
                      </label>
                      <input
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            planKolVred: e.target.value,
                          })
                        }
                        type="text"
                        name="planiranaKolicina"
                        id="planiranaKolicina"
                        className=" pl-3 outline-none mt-1 h-10 bg-gray-50 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-md sm:text-sm border-gray-300 rounded-md"
                      />
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="planPodrska"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Planirana podrska
                      </label>
                      <input
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            planPodrska: parseInt(e.target.value),
                          })
                        }
                        type="number"
                        name="planPodrska"
                        id="planPodrska"
                        className="pl-3 outline-none mt-1 h-10 bg-gray-50 block w-full shadow-md sm:text-sm rounded-md"
                      />
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="potvrPodrska"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Potvrdjena podrska
                      </label>
                      <input
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            potvrPodrska: parseInt(e.target.value),
                          })
                        }
                        type="number"
                        name="potvrPodrska"
                        id="potvrPodrska"
                        className="pl-3 outline-none mt-1 h-10 bg-gray-50 block w-full shadow-md sm:text-sm rounded-md"
                      />
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="potvrdjena"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Potvrdjena
                      </label>
                      <select
                        onChange={(e) => {
                          setFormData({
                            ...formData,
                            potvr: str2bool(e.target.value),
                          });
                        }}
                        id="potvrdjena"
                        name="potvrdjena"
                        className="outline-none mt-1 block w-full py-2 px-3  bg-gray-50 border-gray-300 rounded-md shadow-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                      >
                        <option value={true}>Da</option>
                        <option value={false}>Ne</option>
                      </select>
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="tipPotvrde"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Tip potvrde
                      </label>
                      <select
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            tipPotvrde: {
                              connect: {
                                id: parseInt(e.target.value),
                              },
                            },
                          })
                        }
                        id="tipPotvrde"
                        name="tipPotvrde"
                        className="outline-none mt-1 block w-full py-2 px-3  bg-gray-50 border-gray-300 rounded-md shadow-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                      >
                        {props.tipPotvrde.map((tip) => (
                          <option value={tip.id} key={tip.id}>
                            {tip.naziv}
                          </option>
                        ))}
                      </select>
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="fakturisano"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Fakturisano
                      </label>
                      <select
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            fakturisano: str2bool(e.target.value),
                          })
                        }
                        id="fakturisano"
                        name="fakturisano"
                        className="outline-none mt-1 block w-full py-2 px-3  bg-gray-50 border-gray-300 rounded-md shadow-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                      >
                        <option value={true}>Da</option>
                        <option value={false}>Ne</option>
                      </select>
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="datumFakture"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Datum fakturisanja
                      </label>
                      <input
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            datumFakt: new Date(e.target.value).getTime(),
                          })
                        }
                        type="date"
                        name="datumFakture"
                        id="datumFakture"
                        className="outline-none mt-1 h-10 bg-gray-50 block w-full shadow-md sm:text-sm border-gray-300 rounded-md"
                      />
                    </div>
                    <div className="col-span-6 sm:col-span-3">
                      <label
                        htmlFor="brFakture"
                        className="block text-sm font-medium text-gray-700"
                      >
                        Broj fakture
                      </label>
                      <input
                        onChange={(e) =>
                          setFormData({
                            ...formData,
                            brFakture: e.target.value,
                          })
                        }
                        type="text"
                        name="brFakture"
                        id="brFakture"
                        className="pl-3 outline-none mt-1 h-10 bg-gray-50 block w-full shadow-md sm:text-sm rounded-md"
                      />
                    </div>
                  </div>
                </div>
                <div className="px-4 py-3 space-x-2 bg-gray-50 text-right sm:px-6">
                  <button
                    onClick={handleClose}
                    type="button"
                    className="inline-flex justify-center py-2 px-4 border border-transparent shadow-md text-sm font-medium rounded-md text-white bg-red-500 hover:bg-red-600  focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-400"
                  >
                    Close
                  </button>
                  <button
                    type="submit"
                    className="inline-flex justify-center py-2 px-4 border border-transparent shadow-md text-sm font-medium rounded-md text-white focus:outline-none bg-indigo-600 hover:bg-indigo-700 focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
                  >
                    Add
                  </button>
                </div>
              </div>
            </form>
          </div>
        </Modal.Body>
      </Modal>
    </>
  );
}

export default InputForm;

Oh and I understand that prisma client should have only one instance(like using singleton), but ill fix it later.哦,我知道 Prisma 客户端应该只有一个实例(例如使用单例),但稍后会修复它。

Hope for a fast reply :D希望尽快回复:D

I added onAddInputData={addInputHandler} to InputForm我将 onAddInputData={addInputHandler} 添加到 InputForm

<InputForm
    onAddInputData={addInputHandler}
    tipPotvrde={tipPotvrde}
    tipPodrske={tipPodrske}
/>

Called onAddInputHandler from props inside InputForm.js submitHandler从 InputForm.js submitHandler 内的道具调用 onAddInputHandler

const submitHandler = async (data,e) => {
    e.preventDefault();
    try {
      await fetch("/api/inputs", {
        method: "POST",
        body: JSON.stringify(formData),
      });
      props.onAddInputData(JSON.stringify(formData));
      handleClose();
    } catch (error) {
      console.error(error);
    }
  };

Created a copy of the inputs inside index.js在 index.js 中创建输入的副本

The input variable inside addInputHandler is passed from the InputForm.js addInputHandler 内部的input变量是从 InputForm.js 传递过来的

const [newInputs, setNewInputs] = useState(inputs);

  const addInputHandler = (input) => {
    const JSONInput = JSON.parse(input)
    setNewInputs((prevInputs) => {
      const customJSONforDB = {
        datumUnosa: JSONInput.datumUnosa,
        mesec: JSONInput.mesec,
        pm: JSONInput.pm,
        grupa: JSONInput.grupa,
        opis: JSONInput.opis,
        dobavljac: JSONInput.dobavljac,
        tipPodrske_id: JSONInput.tipPodrske.connect.id,
        tipPodrske: {
          id: JSONInput.tipPodrske.connect.id,
          naziv: tipPodrske.find(
            (type) => type.id === JSONInput.tipPodrske.connect.id
            ).naziv,
          },
          iznos: JSONInput.iznos,
          planKolVred: JSONInput.planKolVred,
          planPodrska: JSONInput.planPodrska,
          potvrPodrska: JSONInput.potvrPodrska,
          tipPotvrde_id: JSONInput.tipPotvrde.connect.id,
          tipPotvrde: {
            id: JSONInput.tipPotvrde.connect.id,
            naziv: tipPotvrde.find(
              (type) => type.id === JSONInput.tipPotvrde.connect.id
              ).naziv,
            },
            potvr: JSONInput.potvr,
            fakturisano: JSONInput.fakturisano,
            datumFakt: JSONInput.datumFakt,
            brFakture: JSONInput.brFakture,
          };
          console.log("customJSONforDB: " + JSON.stringify(customJSONforDB));
          return [...prevInputs, customJSONforDB];
        });
  };

There is probably a much cleaner solution than this but it will do for now.可能有比这更清洁的解决方案,但现在可以了。

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

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