最近读到了一篇文章:Stop Using State for React Forms, There is a Much Better Way!
说的是在react
中,有另外一种更好的方法来存储表单的值
1、state
不好在哪里?
在react
中,当组件的state
或者props
变化时,就会重新渲染组件,更新试图
当我们使用state
来存储表单的状态时,每次输入都会导致试图重新渲染
JavaScript
import { useEffect, useState } from "react";
export default function FormWithState() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
function handleSubmit(e) {
e.preventDefault();
console.log({ email, password });
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>邮箱</label>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<label>密码</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button type="submit">提交</button>
</form>
);
}
但这种渲染在大多数情况下是没有必要的,一般我们只需要在最后点击按钮的时候获取到值即可;有一种方法可以用来避免重新渲染,那就是:使用FormData
!
2、使用FormData
来处理表单
使用js中的FormData
原生接口,只需要将form
表单元素传给构造函数FormData
,它会自动填充表单值
JavaScript
new Form(form)
并给form
表单中的元素一个name
属性,用于获取对应的值
具体做法如下:
JavaScript
import { useEffect, useState } from "react";
export default function FormWithState() {
function handleSubmit(e) {
e.preventDefault();
const form = new Form(e.currentTarget)
// 获取对应的值
const email = form.get('email'),
password = form.get('password')
console.log({ email, password });
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>邮箱</label>
<input
name="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<label>密码</label>
<input
name="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button type="submit">提交</button>
</form>
);
}
3、在vue
中是否也存在该问题
答案:是的
vue
中的表单使用v-model
这个语法糖来实现双向数据绑定,,当它的本质也是通过监听输入框的input
事件,然后将表单最新的值存储在一个变量中,然后再将该变量与value
属性绑定在一起
而这个变量通常是一个响应式数据,我们都知道vue
基于依赖追踪来确定组件是否渲染,当响应式数据变化的时候,视图会重新渲染
这就导致每次输入视图都会重新渲染
所以在vue
中的表单中使用FormData
同样可以达到优化的效果
总结
本文只要总结Stop Using...这篇文章
不管是react
还是vue
,当状态发生变化的时候,组件会重新渲染;而form
表单是一个频繁改变状态的标签,所以当我们使用响应式api
来存储表单状态的时候,会导致每次输入组件都重新渲染
当我们只需要在最后提交时使用form
状态的时候,我们可以在这个时候再去获取form
的状态,这样就不需要维护状态变量,自然也就可以避免组件重复渲染的问题
所以,我们可以在最后通过获取对应的input
标签来获取它的值;不过,有一种更简单的办法:使用FormData
- 把获取值委托给
FormData
,它可以轻松捕获对应的数据
参考: