我是React钩子的新手,并且一直在尝试它们。我正在尝试编写一个usePostForm挂钩,可以在其中复制后状态并将其与新的后字段合并,但是由于某些原因,我一直在遇到无限循环。我想念什么?
let di = this.x - other.x; // distance to the left
let di2 = other.x + 80 - this.x; // distance to the right
let di3 = this.y - other.y; // distance to the top
let di4 = other.y + 150 - this.y; // distance to the bottom
// distance to the center point
let di5 = dist(this.x, this.y, other.x + 80/2, other.y + 150/2);
if (di <= this.r || di2 <= this.r || di3 <= this.r && di4 <= this.r && di5 <= this.r) {
// [...]
}
稍后在另一个函数中,我将其称为
if (min([di, di2, di3, di4, di5]) <= this.r) {
// [...]
}
答案 0 :(得分:1)
如何调用setPost
是关键。在上面的示例中,每次重新发布组件时,它都会一遍又一遍地调用setPost
。
最简单的方法是在form
中设置值。如果使用表单元素,则可以使用event.target
更新useCallback
函数中的值。例如,结合使用useCallback
函数和prevState
回调:
const usePostForm = () => {
const [values, setValues] = React.useState({
title: '',
points: '',
course: '',
question: ''
});
const setFormPost = React.useCallback(
({ target: { name, value } }) =>
setValues(prevState => ({ ...prevState, [name]: value })),
[setValues]
);
return [values, setFormPost];
};
name
和value
来自event.target
的地方:
<input type="text" name="title" value={values.title} onChange={setFormPost} />
我发现这是利用具有多个属性的单个对象状态的最简单方法。然后,您可以在field
中添加handleSubmit
(如果不需要控制),也可以在初始field
调用中添加useState
(如果需要应用)字段作为初始值)。
例如,这通过spread syntax
函数中的useState
初始化值(单击下面的run code snippet
按钮):
const usePostForm = field => {
const [values, setValues] = React.useState({
title: '',
points: '',
course: '',
question: '',
...field
});
const setFormPost = React.useCallback(
({ target: { name, value } }) =>
setValues(prevState => ({ ...prevState, [name]: value })),
[setValues]
);
return [values, setFormPost];
};
const Form = () => {
const [values, setFormPost] = usePostForm({
title: "Initial Title Value",
points: 1
});
const handleSubmit = e => {
e.preventDefault();
alert(JSON.stringify(values, null, 4));
};
return(
<form className="form" onSubmit={handleSubmit}>
<div className="input-container">
<p className="label">Title:</p>
<input
className="input"
type="text"
name="title"
placeholder=""
value={values.title}
onChange={setFormPost}
/>
</div>
<div className="input-container">
<p className="label">Points:</p>
<input
className="input"
type="number"
name="points"
placeholder=""
value={values.points}
onChange={setFormPost}
/>
</div>
<div className="input-container">
<p className="label">Course:</p>
<input
className="input"
type="text"
name="course"
placeholder=""
value={values.course}
onChange={setFormPost}
/>
</div>
<div className="input-container">
<p className="label">Question:</p>
<input
className="input"
type="text"
name="question"
placeholder=""
value={values.question}
onChange={setFormPost}
/>
</div>
<div className="btn-container">
<button className="btn primary" type="submit">Submit</button>
</div>
</form>
);
}
ReactDOM.render(
<Form />,
document.getElementById('root')
);
html {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
font-size: 16px;
font-weight: 400;
line-height: 1.5;
-webkit-text-size-adjust: 100%;
background: #fff;
color: #666;
}
.btn {
color: #fff;
border: 1px solid transparent;
margin: 0 10px;
cursor: pointer;
text-align: center;
box-sizing: border-box;
padding: 0 30px;
vertical-align: middle;
font-size: .875rem;
line-height: 38px;
text-align: center;
text-decoration: none;
text-transform: uppercase;
transition: .1s ease-in-out;
transition-property: color,background-color,border-color;
}
.btn:focus {
outline: 0;
}
.btn-container {
text-align: center;
margin-top: 10px;
}
.form {
width: 550px;
margin: 0 auto;
}
.danger {
background-color: #f0506e;
color: #fff;
border: 1px solid transparent;
}
.danger:hover {
background-color: #ee395b;
color: #fff;
}
.error {
margin: 0;
margin-top: -20px;
padding-left: 26%;
color: red;
text-align: left;
}
.input {
display: inline-block;
height: 40px;
font-size: 16px;
width: 70%;
padding: 0 10px;
background: #fff;
color: #666;
border: 1px solid #e5e5e5;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
transition: .2s ease-in-out;
transition-property: color,background-color,border;
}
.input:focus {
outline: 0;
border: 1px solid #1e87f0;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
}
.input-container {
width: 100%;
height: 60px;
margin-bottom: 20px;
display: inline-block;
}
.label {
width: 25%;
padding-top: 8px;
display: inline-block;
text-align: center;
text-transform: uppercase;
font-weight: bold;
height: 34px;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
background: rgb(238, 238, 238);
}
.primary {
background-color: #1e87f0;
}
.primary:hover {
background-color: #0f7ae5;
color: #fff;
}
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id='root'>
</div>
答案 1 :(得分:0)
请注意,您缺少setFormPost
处的参数:
const setFormPost = field => {
setPost({ ...post, ...field });
};
无限循环取决于调用setFormPost
的位置/哪个上下文(您应该详细说明),我猜它在useEffect
中会导致渲染循环。