javascript - 使用 react 钩子(Hook)时的无限循环

标签 javascript reactjs frontend react-hooks

我是 React hooks 的新手,并且一直在尝试它们。我正在尝试编写一个 usePostForm Hook ,在其中我可以复制后状态并将其与新的后字段合并,但由于某种原因,我不断出现无限循环。我错过了什么?

const usePostForm = field => {
  const [post, setPost] = useState({
    title: '',
    points: '',
    course: '',
    question: ''
  });

  const setFormPost = () => {
    setPost({ ...post, ...field });
  };
  return [post, setFormPost];
};

稍后在另一个函数中,我将其称为

const [post,setPost]=usePostForm()
setPost({title:'hello'})

最佳答案

如何调用 setPost 是关键。在上面的示例中,每次组件重新渲染时,它都会一遍又一遍地调用 setPost

最简单的方法是在表单内设置值。如果您使用表单元素,则可以使用 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];
};

其中namevalue来自event.target:

<input type="text" name="title" value={values.title} onChange={setFormPost} />

我发现这是利用具有多个属性的单个对象状态的最简单方法。然后您可以在 handleSubmit 中添加 field (如果不需要控制)或将 field 添加到您的初始 useState 调用(如果需要将其作为初始值应用于字段)。

例如,这通过 useState 函数中的扩展语法初始化值(单击下面的运行代码片段按钮):

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>

关于javascript - 使用 react 钩子(Hook)时的无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57946107/

相关文章:

javascript - 打印 JavaScript 控制台的堆栈跟踪

Javascript 保留字

javascript - document.getElementById 到 $

javascript - ReactJS 不接受将数组映射到模板的渲染

javascript - 在 Emberjs 中使用每个数据显示嵌套的 json 数据

javascript - 驯服选择 - 不要替换禁用的选项

reactjs - 如何将选择的 defaultValue 限制为 TypeScript 中选项的值之一

reactjs - 在 Elastic Beanstalk 中构建 React 应用程序

javascript - Backbone 路由: optional params in root not matching

html - 我们可以在 HTML5 中使用 <main> 而不是 <div class ="container"> 吗?