问题描述
我正在尝试在 react.js 中实现一个简单的代码,用户可以使用表单输入数据,除非刷新页面,否则数据将显示在表格中。
我在 Code SandBox 中实现了一个代码,它按预期工作。然后我复制了该代码并在 IDE 中使用它。现在相同的代码显示错误为 ==> "TypeError: can't define property "email": Object is not extensible"。 (我用的是intellij IDE终极版)
这是沙箱的链接 => Link for the code in sandbox
如果沙盒不工作,代码它自己==>
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;
沙箱中的输出-->
解决方法
罪魁祸首是下面的行(如果你删除它,它将是下一个 input
行):-
<input required ref={input => this.newData["email"] = input} name="email" value={this.state.items.email} type="email" placeholder="Enter email"/><br></br>
在 ref
的回调中,您将字段名称为 ref
的 email
对象分配给 input
。
如果您继续在 console.log(Object.isExtensible(this.newData)
方法中使用 render
,您会看到它会显示 false
。因此,您试图将 email
属性添加到不允许它的 object
。
您的 codesandbox 正在默默地失败,但您的 IDE 正在严格模式下运行。
您需要根据您的用例将 this.newData
初始化为 object
,方法是将 this.newData
等同于 {email: '',country: '',new_case: '',total_case: '',total_death: ''};
。因此,您的 this.newData
将不再是 React ref
,而只是您的类的实例变量。
这里有帮助的 MDN 链接:-
-
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible
请参阅@Drew 关于如何以更好的方式处理输入的回答。
,在这种情况下确实没有必要使用 React refs,因为您可以轻松地从表单的 onSubmit
事件对象访问字段值。
-
初始状态应该是一个空数组。
this.state = { items: [],};
-
addData
回调需要绑定到它的类的this
。 -
addData
应该从onSubmit
事件对象访问表单字段值。newData
应该是您想要推入items
状态数组的表单字段值的对象。使用功能状态更新从之前的状态进行更新。在items
数组中搜索现有条目时,您需要使用允许检查对象属性的数组函数,因为Array.prototype.includes
实际上只检查引用相等性,您希望搜索具有匹配 {{1 }} 属性使用country
返回布尔值。Array.prototype.some
-
由于您有不受控制的输入,您应该删除旧的“遗留”样式参考附件和
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(); };
道具。示例:value
-
您在尝试呈现错误消息时打错了
<input required name="email" type="email" placeholder="Enter email" />
,它应该是{message !== "" && <p>{this.setState.message}</p>}
。
演示
完整代码:
{message !== "" && <p>{this.state.message}</p>}