[英]NextJS - Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading 'length') when converting a class function to hook function
I'm trying to convert a class function file to hook function but am getting the following error whenever entering text in the field.我正在尝试将 class function 文件转换为挂钩 function 但每当在字段中输入文本时都会收到以下错误。
Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading 'length')未处理的运行时错误类型错误:无法读取未定义的属性(读取“长度”)
I think I've converted everything but just can't find what - am I missing something?我想我已经转换了所有东西,但找不到什么 - 我错过了什么吗?
New hooks code with the above error:带有上述错误的新钩子代码:
import React, { useState } from "react";
function Todo(props) {
const [state, setState] = useState({ items: [], text: "" });
const handleChange = (e) => {
setState({ text: e.target.value });
};
const handleSubmit = (e) => {
e.preventDefault();
if (state.text.length === 0) {
return;
}
const newItem = {
text: state.text,
id: Date.now(),
};
setState((state) => ({
items: state.items.concat(newItem),
text: "",
}));
};
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="new-todo">What needs to be done?</label>
<input id="new-todo" onChange={handleChange} value={state.text} />
<button>Add #{state.items.length + 1}</button>
</form>
<TodoList items={state.items} />
</div>
);
}
function TodoList(props) {
return (
<ul>
{props.items.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}
export default Todo;
Previous class functions file being converted to hooks file above:以前的 class 函数文件被转换为上面的钩子文件:
import React from "react";
class Todo extends React.Component {
constructor(props) {
super(props);
this.state = { items: [], text: "" };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label htmlFor="new-todo">What needs to be done?</label>
<input
id="new-todo"
onChange={this.handleChange}
value={this.state.text}
/>
<button>Add #{this.state.items.length + 1}</button>
</form>
<TodoList items={this.state.items} />
</div>
);
}
handleChange(e) {
this.setState({ text: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
if (this.state.text.length === 0) {
return;
}
const newItem = {
text: this.state.text,
id: Date.now(),
};
this.setState((state) => ({
items: state.items.concat(newItem),
text: "",
}));
}
}
class TodoList extends React.Component {
render() {
return (
<ul>
{this.props.items.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}
}
export default Todo;
Many thanks!非常感谢!
It happens because in handleChange u rewrite whole state with { text: e.target.value } (state hook works differently than class based component state) You should try this:发生这种情况是因为在 handleChange 中你用 { text: e.target.value } 重写整个 state (状态挂钩的工作方式与基于 class 的组件状态不同)你应该试试这个:
const handleChange = (e) => {
setState((prevState) => {...prevState, text: e.target.value });
};
The issue is most likely due to this block of code.该问题很可能是由于此代码块造成的。
const handleChange = (e) => {
setState({ text: e.target.value });
// mutating state as this will overwite the current values with
// {text: e.target.value }
};
a better way of doing this could be to use the rest syntax like this.更好的方法是使用 rest 语法,如下所示。
const handleChange = (e) => {
setState((prev) => { return {...prev, [text]: e.target.value }});
// and now when you update text, it shouldnt overwrite your items or
//vice versa
};
If I had to convert, then I would do it this way.如果我必须转换,那么我会这样做。
import React, { useState } from "react";
const Todo = () => {
const [items, setItems] = useState([]);
const [text, setText] = useState("");
const handleChange = (e) => {
setText(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (text.length === 0) {
return;
}
const newItem = {
text,
id: Date.now()
};
setItems((prevItems) => [...prevItems, newItem]);
// clear the input box after adding.
setText("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<label htmlFor="new-todo">What needs to be done?</label>
<input id="new-todo" onChange={handleChange} value={text} />
<button>Add #{items.length + 1}</button>
</form>
<TodoList items={items} />
</div>
);
};
const TodoList = (props) => {
const { items } = props;
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
};
export default Todo;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.