I'm studying about react, I've made a form to save data with react, I want to update the table again as data is saved, I've used setState for this purpose, The issue is state updating but not rendering, I've tried some ways to find the issue,
here's my code
import React, { Component } from "react";
import Header from "../header";
import Table from "./table";
import Addbox from "./create__box";
import $ from "jquery";
import { Api__url } from "../../vars";
class index extends Component {
constructor(props) {
super(props);
// binding functions
this.getData = this.getData.bind(this);
this.table = this.table.bind(this);
this.show_create_box = this.show_create_box.bind(this);
// using state
this.state = {
data: "Fetching Records....",
create_box: "",
};
}
getData() {
$.ajax({
type: "POST",
url: `${Api__url}services/get`,
dataType: "JSON",
success: this.table,
});
}
table(d) {
this.setState({ data: <Table data={d} /> });
}
show_create_box() {
this.setState({create_box: <Addbox top="15vh" again_get_data={this.getData}/>});
}
componentDidMount() {
this.getData();
}
render() {
return (
<>
<Header />
<div className="container mt-5 px-5">
<div className="border__box p-2 col">
<div className="row m-0 px-3">
<div className="col">
<h2>Services in home page</h2>
</div>
<div className="col d-flex justify-content-end">
<button
onClick={this.show_create_box}
className="btn btn-outline-success show__create__box"
>
Add New Data
</button>
</div>
</div>
<div className="row m-0 py-2 px-4">{this.state.data}</div>
</div>
</div>
{this.state.create_box}
</>
);
}
}
export default index;
```
the code from the table file
```
import React, { Component } from "react";
import Updatebox from "./update__box";
class table extends Component {
constructor(props) {
super(props);
this.show_update_box = this.show_update_box.bind(this);
this.delete_record = this.delete_record.bind(this);
this.state = { update_box: "" };
// making data
this.tbody = props.data.map((d, index) => {
return (
<tr className="w-100 row m-0 p-0" id={d.services_id}>
<th className="col-1" scope="row">
{index + 1}
</th>
<td className="col-3">{d.services_name}</td>
<td className="col-4">{d.services_description}</td>
<td className="col-2">{d.services_icon}</td>
<td className="col-1">
<button
onClick={() => {
this.show_update_box(index);
}}
className="btn btn-outline-success"
>
Update
</button>
</td>
<td className="col-1">
<button
onClick={() => {
this.delete_record(index);
}}
className="btn btn-outline-danger"
>
Delete
</button>
</td>
</tr>
);
});
}
// Function to get close form instruction from another class
changeStuff(d) {
this.setState(d);
}
delete_record(id) {
alert(id);
}
show_update_box(key) {
this.setState({
update_box: (
<Updatebox
data={this.props.data[key]}
changeHandler={this.changeStuff.bind(this)}
/>
),
});
}
render() {
return (
<>
<table className="position-relative table table-hover ">
<thead className="table-dark">
<tr className="row m-0 p-0">
<th className="col-1">Sr #</th>
<th className="col-3">Name</th>
<th className="col-4">Description</th>
<th className="col-2">Icon</th>
<th className="col-1">Update</th>
<th className="col-1">Delete</th>
</tr>
</thead>
<tbody>{this.tbody}</tbody>
</table>
{this.state.update_box}
</>
);
}
}
export default table;
```
here's the code for creating the box
```
import React, { Component } from "react";
import CloseIcon from "@mui/icons-material/Close";
import $ from "jquery";
// import i from "./index";
export default class Addbox extends Component {
constructor(props) {
super(props);
this.data = { name: "", description: "", icon: "" };
this.state = this.data;
this.change = this.change.bind(this);
this.submit = this.submit.bind(this);
this.changeCSS = this.changeCSS.bind(this);
this.setCSS = this.setCSS.bind(this);
this.close_create_box = this.close_create_box.bind(this);
}
close_create_box() {
this.props.changeHandler({ create_box: "" });
}
change(e) {
var name = e.target.name;
var value = e.target.value;
this.setState({
[name]: value,
});
}
changeCSS() {
$("#create").removeClass("btn-outline-success");
$("#create").addClass("btn-outline-dark");
$("#create").prop("disabled", true);
$("#create").text("Sending....");
}
setCSS() {
$("#create").removeClass("btn-outline-dark");
$("#create").addClass("btn-outline-success");
$("#create").prop("disabled", false);
$("#create").text("Submit");
}
submit(e) {
e.preventDefault();
$.ajax({
type: "POST",
url: "http://127.0.0.1:8000/api/services/create",
data: this.state,
dataType: "JSON",
beforeSend: this.changeCSS,
success: (e) => {
alert(e.message);
this.props.again_get_data();
this.close_create_box();
},
error: (e) => {
this.setCSS();
alert(e.responseText);
},
});
}
render() {
return (
<form
onSubmit={this.submit}
className="add__box create__box"
method="POST"
style={{ top: this.props.top }}
>
<div className="mb-3 row">
<div className="col-10">
<h4>Add New Service</h4>
</div>
<div className="col-2">
<CloseIcon className="close" onClick={this.close_create_box} />
</div>
</div>
<div className="mb-3">
<label htmlFor="create_name" className="form-label">
Name
</label>
<input
id="create_name"
name="name"
type="text"
className="form-control"
onChange={this.change}
value={this.state.name}
required
minLength={10}
maxLength={100}
/>
</div>
<div className="mb-3">
<label htmlFor="create_desc" className="form-label">
Description
</label>
<textarea
id="create_desc"
className="form-control"
onChange={this.change}
required
value={this.state.description}
minLength={20}
name="description"
></textarea>
</div>
<div className="mb-3">
<label htmlFor="create_icon" className="form-label">
Icon
</label>
<input
id="create_icon"
type="text"
className="form-control"
onChange={this.change}
value={this.state.icon}
required
name="icon"
/>
</div>
<div className="m-5 row my-0">
<button id="create" type="submit" className="btn btn-outline-success">
Submit
</button>
</div>
</form>
);
}
}
```
as per react docs, UI components shouldn't be in state and it should only contain the minimal amount of data needed to represent your UI's state.
so instead of adding a UI element in the state, you should just add a minimal amount of data in it
Here's an example based on your code
constructor(props) {
...
this.state = {
status: "loading",
data: "Fetching Records....",
create_box: "",
};
}
table(d) {
this.setState({ data: d, status: "table" });
}
renderData() {
const d = this.state.data
const status = this.state.status
if (status == "loading") { return d }
if (status == "table") { return <Table data={d} /> }
}
render() {
return (
<>
...
<div className="row m-0 py-2 px-4">{renderData()}</div>
...
</>
);
}