I am trying to implement a simple code in react.js which user can input the data using form and unless the page is refreshed the data will show in the table.
I have implemented a code in Code Sandbox and it worked as expected. Then I copied that code and used it in the IDE. Now the same code is showing error as ==> "TypeError: can't define property "email": Object is not extensible". (I am using intellij IDE ultimate edition)
This is the link for sandbox => Link for the code in sandbox
The code it self if the sand box is not working ==>
import React, {Component} from "react";
class CustomDetails extends Component {
constructor(props) {
super(props);
this.state = {
items: [{email: '', country: '', new_case: '', total_case: '', total_death: ''}],
message: ''
}
this.newData = React.createRef();
this.addForm = React.createRef();
}
addData(e) {
e.preventDefault();
const {items} = this.state;
const newData = () => ({
email:this.addForm.email.value,
country:this.addForm.country.value,
new_case:this.addForm.new_case.value,
total_case:this.addForm.total_case.value,
total_death:this.addForm.total_death.value
})
const isOnTheList = items.includes(newData.country);
if (isOnTheList) {
this.setState(({
message: 'This country details are already added.'
}))
} else {
this.setState({
items: [...this.state.items, newData()],
})
}
this.addForm.reset();
}
render() {
const {items, message}=this.state;
return (
<div>
<div>
<div>
<form ref={input => this.addForm = input} onSubmit={(e) => {
this.addData(e)
}}>
<label>User Email :</label><br/>
<input required ref={input => this.newData["email"] = input} name="email" value={this.state.items.email}
type="email"
placeholder="Enter email"/><br></br>
<label>Country :</label><br/>
<input required ref={input => this.newData["country"] = input} name="country" value={this.state.items.country}
type="text"
placeholder="Enter country"/><br></br>
<label>New Cases :</label><br/>
<input required ref={input => this.newData["new_case"] = input}
name="new_case"
value={this.state.items.new_case} type="text"
placeholder="Enter no of new cases"/><br></br>
<label>Total cases :</label><br/>
<input required ref={input => this.newData["total_case"] = input}
name="total_case"
value={this.state.items.total_case} type="text"
placeholder="Enter no of total cases"/><br></br>
<label>Total death :</label><br/>
<input required ref={input => this.newData["total_death"] = input}
name="total_death"
value={this.state.items.total_death} type="text"
placeholder="Enter no of total deaths"/><br></br>
<button variant="primary" type="submit">
Submit</button><br></br>
</form>
</div>
<div>
{
message !== '' && <p>{this.setState.message}</p>
}
<table striped="true" bordered="true" hover="true">
<thead>
<tr>
<th>Email</th>
<th>Country</th>
<th>New cases</th>
<th>Total cases</th>
<th>Total deaths</th>
</tr>
</thead>
<tbody>
{items.map((item,index) => {
return (
<tr key={index}>
<td>{item.email}</td>
<td>{item.country}</td>
<td>{item.new_case}</td>
<td>{item.total_case}</td>
<td>{item.total_death}</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
</div>
)
}}export default CustomDetails;
There really isn't a point to using React refs in this case as you can easily access the field values from the form's onSubmit
event object.
Initial state should be an empty array.
this.state = {
items: [],
};
The addData
callback needs this
of the class bound to it.
addData
should access the form field values from the onSubmit
event object. The newData
should be an object of the form field values you want to push into your items
state array. Use a functional state update to update from the previous state. When searching the items
array for existing entries you need to use an array function that allows examining object properties as Array.prototype.includes
really only check reference equality, you want to search for an item that has a matching country
property using Array.prototype.some
to return a boolean.
addData = (e) => {
e.preventDefault();
const { items } = this.state;
const newData = {
email: e.target.email.value,
country: e.target.country.value,
new_case: e.target.new_case.value,
total_case: e.target.total_case.value,
total_death: e.target.total_death.value
};
const isOnTheList = items.some(item => item.country === newData.country);
if (isOnTheList) {
this.setState({
message: "This country details are already added."
});
} else {
this.setState((prevState) => ({
items: [...prevState.items, newData]
}));
}
e.target.reset();
};
Since you've uncontrolled inputs you should remove the old "legacy" style ref attachments and value
prop. Example:
<input
required
name="email"
type="email"
placeholder="Enter email"
/>
You've a typo when trying to render an error message, {message !== "" && <p>{this.setState.message}</p>}
, it should be {message !== "" && <p>{this.state.message}</p>}
.
Full code:
class CustomDetails extends Component {
constructor(props) {
super(props);
this.state = {
items: [],
message: ""
};
}
addData = (e) => {
e.preventDefault();
const { items } = this.state;
const newData = {
email: e.target.email.value,
country: e.target.country.value,
new_case: e.target.new_case.value,
total_case: e.target.total_case.value,
total_death: e.target.total_death.value
};
const isOnTheList = items.includes(newData.country);
if (isOnTheList) {
this.setState({
message: "This country details are already added."
});
} else {
this.setState((prevState) => ({
items: [...prevState.items, newData]
}));
}
e.target.reset();
};
render() {
const { items, message } = this.state;
return (
<div>
<div>
<div>
<form onSubmit={this.addData}>
<label>User Email :</label>
<br />
<input
required
name="email"
type="email"
placeholder="Enter email"
/>
<br></br>
<label>Country :</label>
<br />
<input
required
name="country"
type="text"
placeholder="Enter country"
/>
<br></br>
<label>New Cases :</label>
<br />
<input
required
name="new_case"
type="text"
placeholder="Enter no of new cases"
/>
<br></br>
<label>Total cases :</label>
<br />
<input
required
name="total_case"
type="text"
placeholder="Enter no of total cases"
/>
<br></br>
<label>Total death :</label>
<br />
<input
required
name="total_death"
type="text"
placeholder="Enter no of total deaths"
/>
<br></br>
<button variant="primary" type="submit">
Submit
</button>
<br></br>
</form>
</div>
<div>
{message !== "" && <p>{this.state.message}</p>}
<table striped="true" bordered="true" hover="true">
<thead>
<tr>
<th>Email</th>
<th>Country</th>
<th>New cases</th>
<th>Total cases</th>
<th>Total deaths</th>
</tr>
</thead>
<tbody>
{items.map((item, index) => {
return (
<tr key={index}>
<td>{item.email}</td>
<td>{item.country}</td>
<td>{item.new_case}</td>
<td>{item.total_case}</td>
<td>{item.total_death}</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
</div>
);
}
}