在道具改变时重新渲染组件



我是react世界的新手,我需要帮助。

我有一个问题,重新呈现数据在我的表组件。当我创建一个新的API调用时,我在使用Prisma的DB中创建一个新条目,新数据不会在DataTableMaterial组件中重新呈现。DataTableMaterial作为道具从DB (getServerSideProps中的Prisma调用)中获取元素数组。我的问题是如何重新呈现我的表,当我提交我的表格添加新数据到数据库?

我用:节点:v16.9.1npm: 8.0.0棱镜:3.2.1之上下:最新

My 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;

这是我的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,
},
};
}

这是我的API调用从submitFormHandler

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);
}
};

从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

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;

噢,我明白prisma客户端应该只有一个实例(就像使用singleton一样),但我稍后会修复它。

希望尽快回复:D

我将onAddInputData={addInputHandler}添加到InputForm

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

从InputForm.js中的props调用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);
}
};

在index.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];
});
};

可能有一个比这更干净的解决方案,但它现在就可以了。