【问题标题】:Using Hook to control form fields with an Object使用 Hook 控制带有 Object 的表单域
【发布时间】:2024-05-19 04:25:02
【问题描述】:

我想创建一个表单来编辑使用配置文件。该表单呈现来自user 对象的数据。我想使用 React 的 useState Hook 来保存表单的状态,并且我想保留一个对象来使用处理整个用户对象更改的 onChange 函数来跟踪表单的更改。为什么这不起作用?

function Profile() {

  const [user, setUser] = useState({});
  const [errors, setErrors] = useState({});

  useEffect(() => {
    axios.get(`/api/v1/users/me`)
      .then(res => setUser(res.data.user))
  }, [])

  const onChange = e => {
    user[e.target.name] = e.target.value;
    setUser(user)
  }

  return (
    < div >
      <form onSubmit={null}>
        <div className="form-group">
          <label htmlFor={user.name}>Name</label>
          <input type="text" name="name"
            className={`form-control form-control-lg ${errors.name ? 'is-invalid' : ''}`}
            onChange={onChange} placeholder="Fred Flintstone" value={user.name || ''}
          />
        </div>
        <div className="form-group">
          <label htmlFor="email">Email</label>
          <input type="email" name="email"
            className={`form-control form-control-lg ${errors.email ? 'is-invalid' : ''}`}
            onChange={onChange} placeholder="fred.flintstone@aol.com" value={user.email || ''}
          />
        </div>
        <div className="form-group">
          <label htmlFor="username">Username</label>
          <input type="text" name="username"
            className={`form-control form-control-lg ${errors.username ? 'is-invalid' : ''}`}
            onChange={onChange} placeholder="yabadabadu" value={user.username || ''}
          />
        </div>
      </form>
      <div>
        <button type="button" className="btn btn-light btn-sm float-right" onClick={() => console.log("Logout")}>Logout</button>
      </div>
    </div >
  )
}

【问题讨论】:

标签: javascript reactjs react-hooks


【解决方案1】:

您正在就地修改用户对象。当您调用 setUser(user) 时,表单不会重新呈现,因为用户对象的身份没有改变。

你在哪里:

  const onChange = e => {
    user[e.target.name] = e.target.value;
    setUser(user)
  }

你想要的东西是这样的:

  const onChange = useCallback((event) => {
    const {name, value} = event.target;
    setUser(oldUser => {
      return {
        ...user,
        [name]: value,
      };
    });
  }, [setUser]);

作为一般经验法则,您通常不希望在 React 中就地修改状态对象。

【讨论】:

  • 我认为 user 也应该在依赖项中,或者您可以使用回调形式 setUser(oldUser =&gt; ({/**/})) 代替。
  • 哎呀。我的意思是在那里写回调表单!
  • 谢谢埃米尔!
  • 但是,你会遇到另一个问题,event pooling in React 会因为异步使用事件而搞砸,Dennis' answer 是对的。
  • 好理查德和艾米莉。非常感谢您的支持。我得到了它的工作: const onChange = e => { setUser({ ...user, [e.target.name]: [e.target.value] }) }
【解决方案2】:

你应该复制users,否则它不会触发渲染阶段,因为 React 会与之前的状态进行浅比较。

const onChange = ({ target: { name, value } }) => {
  setUser(user => ({ ...user, [name]: value }));
};

setState() 总是会导致重新渲染,除非 shouldComponentUpdate() 返回false。如果正在使用可变对象并且在 shouldComponentUpdate() 中无法实现条件渲染逻辑,仅在新状态与先前状态不同时调用 setState() 将避免不必要的重新渲染

【讨论】:

    最近更新 更多