作为前提,这是我第一次使用 React 作为前端、Rails 作为后端创建 Web 应用程序,因此对于任何巨大的错误,我提前表示歉意。我尝试寻找同样的问题,但尚未找到任何解决方案。
问题:
我有一张包含员工数据的表。为了添加新员工,我从 React 中的表单收集数据,并向 Rails API 发出 POST 请求。数据成功保存在后端后,我希望应用程序使用新添加的员工重新渲染表。
现在,数据已成功从 React 传输到 API 并正确保存在后端,但是保存数据后,一切都会崩溃,并且表不会重新渲染,除非经过一段时间(<1 min).
代码:
这是员工控制器(为了简单起见,我只发布了创建函数):
#employees_controller.rb
class Api::V1::EmployeesController < ApplicationController
# POST /employees
def create
@employee = Employee.new(employee_param)
if @employee.save!
render json: @employee, status: :created, location: api_v1_employees_path(@employee)
else
render json: @employee.errors, status: :unprocessed_entity
end
end
private
def employee_param
params.require(:employee).permit(:fullname, :email, :phone_number, :company, :is_admin)
end
end
我认为它工作得很好,因为数据已成功保存在正确的位置,并且我可以看到它们显示在索引中。
这是显示员工数据的 React 表:
// DataTable.js
// DataTable component (shows the employees data)
import React from "react";
import {
TableContainer,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from "@mui/material";
import { withStyles } from "@material-ui/core/styles";
const StyledTableHeaderCell = withStyles({
root: {
color: "#232020",
fontSize: "12px",
fontWeight: "bold",
lineHeight: "150%",
fontFamily: "Poppins",
},
})(TableCell);
const StyledTableCell = withStyles({
root: {
color: "#232020",
fontSize: "12px",
lineHeight: "150%",
fontFamily: "Poppins",
},
})(TableCell);
function DataTable({ header, employeesData }) {
console.log(typeof employeesData);
console.log(employeesData);
return (
<TableContainer
sx={{
maxHeight: 440,
minWidth: 650,
overflow: "auto",
width: "95%",
marginTop: "37px",
borderRadius: "10px",
border: "1px solid #E6EDFF",
}}
>
<Table stickyHeader aria-label="sticky table">
<TableHead sx={{ display: "table-header-group" }}>
<TableRow>
{header.map((field, idx) => {
return { idx } === 0 ? (
<StyledTableHeaderCell key={idx}>{field}</StyledTableHeaderCell>
) : (
<StyledTableHeaderCell align="right" key={idx}>
{field}
</StyledTableHeaderCell>
);
})}
</TableRow>
</TableHead>
<TableBody>
{employeesData.map((employee, idx) => {
return (
<TableRow
key={idx}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<StyledTableHeaderCell component="th" scope="row">
{employee.fullname}
</StyledTableHeaderCell>
<StyledTableCell align="right">
{employee.company}
</StyledTableCell>
<StyledTableCell align="right">
{employee.email}
</StyledTableCell>
<StyledTableCell align="right">
{employee.phone_number}
</StyledTableCell>
<StyledTableCell align="right">
{employee.is_admin ? "Admin" : "Tecnico"}
</StyledTableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
);
}
export default DataTable;
其中对象EmployeeData作为该组件的道具传递:
// Employees.js
// Employees index
import React from "react";
import axios from "axios";
import { useEffect, useState } from "react";
import DataTable from "../shared/DataTable";
import BtnContainer from "../components/buttonsdiv";
import Box from "@mui/material/Box";
const API_URL = "http://localhost:3000/api/v1/employees";
function getAPIData(params) {
return axios.get(API_URL).then((response) => response.data);
}
function EmployeesPage() {
const [employees, setEmployees] = useState();
useEffect(() => {
let mounted = true;
getAPIData().then((items) => {
if (mounted) {
setEmployees(items);
}
});
return () => (mounted = false);
}, []);
// Callback function to receive data from the child component
const handleFormSubmit = (data) => {
setEmployees((prev) => ({ ...prev, data }));
};
return (
<Box>
// the component BtnContainer contains the button that triggers the form that gets the employee data and the form itself
<BtnContainer
apiURL={API_URL}
text="Aggiungi impiegato"
onFormSubmit={handleFormSubmit}
formTitle="Aggiungi nuovo impiegato"
/>
{employees === undefined ? (
<p>Loading...</p>
) : (
// DataTable is the table that displays the employees data
<DataTable
header={["Nome", "Società", "Email", "Telefono", "Ruolo"]}
employeesData={employees}
/>
)}
</Box>
);
}
export default EmployeesPage;
我的假设和我已经尝试过的:
我认为问题在于,一旦我将数据发送到 API 并重新渲染页面,员工对象仍然没有填充数据,因此它是未定义的。我尝试添加一个条件,如果对象未定义而不是表,它会显示正在加载的东西,但它不起作用。所以我有点迷失:,)
通过替换这一行解决了问题
setEmployees((prev) => ({ ...prev, data }));
有了这个
setEmployees((prev) => [...prev, data]);
在Employees.js 文件中。