[英]Infinite loop when using react hooks
I am new to React hooks and have been experimenting with them. 我是React钩子的新手,并且一直在尝试它们。 I am trying to write a usePostForm hook, where I can copy the post-state and merge it with the new post field but for some reason, I keep getting an infinite loop.
我正在尝试编写一个usePostForm挂钩,可以在其中复制后状态并将其与新的后字段合并,但是由于某些原因,我一直在遇到无限循环。 What am I missing?
我想念什么?
const usePostForm = field => {
const [post, setPost] = useState({
title: '',
points: '',
course: '',
question: ''
});
const setFormPost = () => {
setPost({ ...post, ...field });
};
return [post, setFormPost];
};
Later in another function, I am calling it as 稍后在另一个函数中,我将其称为
const [post,setPost]=usePostForm()
setPost({title:'hello'})
How you're invoking the setPost
is key. 您如何调用
setPost
是关键。 In the example above, every time the component rerenders it invokes the setPost
over and over. 在上面的示例中,每次重新渲染组件时,它
setPost
反复调用setPost
。
The easiest approach would be to set values from within a form
. 最简单的方法是从
form
设置值。 If you're using form elements, you can use event.target
to update the values in a useCallback
function. 如果使用表单元素,则可以使用
event.target
来更新useCallback
函数中的值。 For example, using the useCallback
function in combination with the prevState
callback: 例如,结合使用
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];
};
Where name
and value
are coming from event.target
: name
和value
来自event.target
:
<input type="text" name="title" value={values.title} onChange={setFormPost} />
I found this to be the easiest way to utilize a single object state with multiple properties. 我发现这是利用具有多个属性的单个对象状态的最简单方法。 Then you can either add
field
in handleSubmit
(if it doen't need to be controlled) or add field
to your initial useState
call (if it needs to be applied to a field as an initial value). 然后,您可以在
handleSubmit
添加field
(如果不需要控制),也可以将field
添加到您的初始useState
调用中(如果需要将它作为初始值应用于字段)。
For example, this initializes values via the spread syntax
within the useState
function (click the run code snippet
button below): 例如,这通过
useState
函数内的spread syntax
初始化值(单击下面的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>
Take note that you are missing an argument at setFormPost
: 请注意,您缺少
setFormPost
的参数:
const setFormPost = field => {
setPost({ ...post, ...field });
};
The infinite loop depends on where/which context you calling setFormPost
(you should elaborate more), my guess it's in useEffect
which causes a render loop. 无限循环取决于调用
setFormPost
位置/哪个上下文(您应该详细说明),我猜它在useEffect
,这会导致渲染循环。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.