为什么不验证 eventListener 上的输入?
why doesn't validating input on eventListener work?
你能帮我让这个沙盒工作吗?
我想念一些东西。
当密码或登录名的长度超过 3 时,我希望在输入附近看到“GOOD”而不是“FAIL”。
这里是 link:https://codesandbox.io/s/competent-bogdan-5604u?file=/src/App.js
谢谢!
有一些问题,但它们都来自同一个根源 - 状态更新不会立即发生。
问题一是您无法在调用 setState
后立即使用更新后的状态。这导致您的验证逻辑使用 previous 渲染中的表单值执行。
问题二是如果你连续两次调用状态更新函数,它只会使用最后一个值。因此,在您的验证逻辑中,您根据 login
的值调用一次 setFormError
,并根据 password
的值调用一次。这意味着永远不会使用由 login
逻辑确定的值。
我已经写了一个例子,你可以用几种方法正确地写这个。
示例一作为每次输入更改时调用的函数:
const { useState } = React;
const MyInput = (props) => {
return (
<input {...props} style={{ border: "1px solid red", outline: "none" }} />
);
};
const Example = () => {
const [form, setForm] = useState({
login: "",
password: ""
});
const [formError, setFormError] = useState({
isValidLogin: "FAIL",
isValidPassword: "FAIL"
});
const handleValidateForm = (newForm) => {
let newValid = {...formError}; // Use a new object so we only update state once
if (newForm.login.length > 3) {
newValid.isValidLogin = "GOOD"
} else {
newValid.isValidLogin = "FAIL"
}
if (newForm.password.length > 3) {
newValid.isValidPassword = "GOOD"
} else {
newValid.isValidPassword = "FAIL"
}
setFormError(newValid);
};
const onChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
const newForm = {...form, [name]: value}; // Set to new object
setForm(newForm);
handleValidateForm(newForm); // Send the new object so its up-to-date
};
return (
<div>
<div>
<MyInput type="text" name="login" onChange={onChange} />{" "}
{formError.isValidLogin}
<br />
<MyInput type="text" name="password" onChange={onChange} />{" "}
{formError.isValidPassword}
</div>
</div>
);
};
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
另一种方法是将验证移至 useEffect
:
const { useState, useEffect } = React;
const MyInput = (props) => {
return (
<input {...props} style={{ border: "1px solid red", outline: "none" }} />
);
};
const Example = () => {
const [form, setForm] = useState({
login: "",
password: ""
});
const [formError, setFormError] = useState({
isValidLogin: "FAIL",
isValidPassword: "FAIL"
});
useEffect(() => {
let newValid = {...formError}; // Use a new object so we only update state once
if (form.login.length > 3) {
newValid.isValidLogin = "GOOD"
} else {
newValid.isValidLogin = "FAIL"
}
if (form.password.length > 3) {
newValid.isValidPassword = "GOOD"
} else {
newValid.isValidPassword = "FAIL"
}
setFormError(newValid);
}, [form]); // Runs every time the form changes
const onChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
setForm({...form, [name]: value});
};
return (
<div>
<div>
<MyInput type="text" name="login" onChange={onChange} />{" "}
{formError.isValidLogin}
<br />
<MyInput type="text" name="password" onChange={onChange} />{" "}
{formError.isValidPassword}
</div>
</div>
);
};
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
效果一样,就看你喜欢哪种模式了。
你能帮我让这个沙盒工作吗? 我想念一些东西。
当密码或登录名的长度超过 3 时,我希望在输入附近看到“GOOD”而不是“FAIL”。
这里是 link:https://codesandbox.io/s/competent-bogdan-5604u?file=/src/App.js
谢谢!
有一些问题,但它们都来自同一个根源 - 状态更新不会立即发生。
问题一是您无法在调用 setState
后立即使用更新后的状态。这导致您的验证逻辑使用 previous 渲染中的表单值执行。
问题二是如果你连续两次调用状态更新函数,它只会使用最后一个值。因此,在您的验证逻辑中,您根据 login
的值调用一次 setFormError
,并根据 password
的值调用一次。这意味着永远不会使用由 login
逻辑确定的值。
我已经写了一个例子,你可以用几种方法正确地写这个。
示例一作为每次输入更改时调用的函数:
const { useState } = React;
const MyInput = (props) => {
return (
<input {...props} style={{ border: "1px solid red", outline: "none" }} />
);
};
const Example = () => {
const [form, setForm] = useState({
login: "",
password: ""
});
const [formError, setFormError] = useState({
isValidLogin: "FAIL",
isValidPassword: "FAIL"
});
const handleValidateForm = (newForm) => {
let newValid = {...formError}; // Use a new object so we only update state once
if (newForm.login.length > 3) {
newValid.isValidLogin = "GOOD"
} else {
newValid.isValidLogin = "FAIL"
}
if (newForm.password.length > 3) {
newValid.isValidPassword = "GOOD"
} else {
newValid.isValidPassword = "FAIL"
}
setFormError(newValid);
};
const onChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
const newForm = {...form, [name]: value}; // Set to new object
setForm(newForm);
handleValidateForm(newForm); // Send the new object so its up-to-date
};
return (
<div>
<div>
<MyInput type="text" name="login" onChange={onChange} />{" "}
{formError.isValidLogin}
<br />
<MyInput type="text" name="password" onChange={onChange} />{" "}
{formError.isValidPassword}
</div>
</div>
);
};
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
另一种方法是将验证移至 useEffect
:
const { useState, useEffect } = React;
const MyInput = (props) => {
return (
<input {...props} style={{ border: "1px solid red", outline: "none" }} />
);
};
const Example = () => {
const [form, setForm] = useState({
login: "",
password: ""
});
const [formError, setFormError] = useState({
isValidLogin: "FAIL",
isValidPassword: "FAIL"
});
useEffect(() => {
let newValid = {...formError}; // Use a new object so we only update state once
if (form.login.length > 3) {
newValid.isValidLogin = "GOOD"
} else {
newValid.isValidLogin = "FAIL"
}
if (form.password.length > 3) {
newValid.isValidPassword = "GOOD"
} else {
newValid.isValidPassword = "FAIL"
}
setFormError(newValid);
}, [form]); // Runs every time the form changes
const onChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
setForm({...form, [name]: value});
};
return (
<div>
<div>
<MyInput type="text" name="login" onChange={onChange} />{" "}
{formError.isValidLogin}
<br />
<MyInput type="text" name="password" onChange={onChange} />{" "}
{formError.isValidPassword}
</div>
</div>
);
};
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
效果一样,就看你喜欢哪种模式了。