使用React挂钩时的无限循环

时间:2019-09-15 16:35:26

标签: javascript reactjs frontend react-hooks

我是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) {
    // [...]
}

2 个答案:

答案 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];
};

namevalue来自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中会导致渲染循环。