简体   繁体   English

使用React挂钩时的无限循环

[英]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 : namevalue来自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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM