[英]Using React.memo with hooks for controlled inputs
I'm providing some form functionality from a custom React hook. 我从自定义的React钩子提供了一些表单功能。 This hook has some functionality similar to Formik (but this is really basic stuff).
这个钩子具有一些与Formik类似的功能(但这实际上是基本的东西)。
function useFormValidation(initialState, validate) {
const [values, setValues] = React.useState(initialState);
const [errors, setErrors] = React.useState({});
const [isSubmitting, setSubmitting] = React.useState(false);
React.useEffect(() => {
if (isSubmitting) {
const noErrors = Object.keys(errors).length === 0;
if (noErrors) {
console.log("authenticated!", values.email, values.password);
setSubmitting(false);
} else {
setSubmitting(false);
}
}
}, [errors]);
function handleChange(event) {
setValues({
...values,
[event.target.name]: event.target.value
});
}
function handleBlur() {
const validationErrors = validate(values);
setErrors(validationErrors);
}
function handleSubmit(event) {
event.preventDefault();
const validationErrors = validate(values);
setErrors(validationErrors);
setSubmitting(true);
}
return {
handleSubmit,
handleChange,
handleBlur,
values,
errors,
isSubmitting
};
}
The form is the following: 形式如下:
function Register() {
const {
handleSubmit,
handleChange,
handleBlur,
values,
errors,
isSubmitting
} = useFormValidation(INITIAL_STATE, validateAuth);
// const [email, setEmail] = React.useState("");
// const [password, setPassword] = React.useState("");
return (
<div className="container">
<h1>Register Here</h1>
<form onSubmit={handleSubmit}>
<Input
handleChange={handleChange}
handleBlur={handleBlur}
name="email"
value={values.email}
className={errors.email && "error-input"}
autoComplete="off"
placeholder="Your email address"
/>
{errors.email && <p className="error-text">{errors.email}</p>}
<Input
handleChange={handleChange}
handleBlur={handleBlur}
value={values.password}
className={errors.password && "error-input"}
name="password"
// type="password"
placeholder="Choose a safe password"
/>
{errors.password && <p className="error-text">{errors.password}</p>}
<div>
<button disabled={isSubmitting} type="submit">
Submit
</button>
</div>
</form>
</div>
);
}
And the memoized component is the next: 记忆的组件是下一个:
function Input({
handleChange,
handleBlur,
name,
value,
className,
autoComplete,
placeholder,
type
}) {
return (
<input
onChange={handleChange}
onBlur={handleBlur}
name={name}
value={value}
className={className}
autoComplete={autoComplete}
placeholder={placeholder}
type={type}
/>
);
}
function areEqual(prevProps, nextProps) {
console.log(`
prevProps: ${JSON.stringify(prevProps.value)}
nextProps: ${JSON.stringify(nextProps.value)}
`);
return prevProps.value === nextProps.value;
}
const useMemo = (component, propsAreEqual) => {
return memo(component, propsAreEqual);
};
export default useMemo(Input, areEqual);
I enter some text into the first input. 我在第一个输入中输入一些文本。 Then, when I switch to the second Input and start typing, the first input loses the value.
然后,当我切换到第二个Input并开始键入时,第一个Input失去了值。 It's like the form is not rendering the LAST MEMOIZED input, but prior versions instead.
就像表单没有呈现LAST MEMOIZED输入,而是呈现以前的版本。 I'm a React beginner and can't figure out the solution.
我是React的初学者,无法解决问题。 Any help please?
有什么帮助吗?
Try using the updater form of setState
which takes a function: 尝试使用带有功能的
setState
的更新程序形式:
function handleChange(event) {
// event.target wont be available when fn is run in setState
// so we save them in our own local variables here
const { name, value } = event.target;
setValues(prev => ({
...prev,
[name]: value
}));
}
Your areEqual
method translates to 您的
areEqual
方法转换为
Re-render my Input ONLY when the
value
changes.仅在
value
更改时才重新渲染我的输入。
But in reality, your handleChange
function from the hook is also changing. 但实际上,挂钩中的
handleChange
函数也在发生变化。 Also, you use the same handleChange
for both the inputs. 另外,您对两个输入使用相同的
handleChange
。 So, the Input
"remembers" only the handleChange
from the last time value
had changed and since handleChange
is tracking values
via closure, it in-turn "remembers" the values
when it was created. 因此,
Input
handleChange
上次更改value
起“记住” handleChange
,并且由于handleChange
通过闭包跟踪values
,因此它在创建时依次“记住” values
。
Changing your areEqual
method (or completely omitting it) to verify a change in handleChange
, will solve your problem. 更改
areEqual
方法(或完全省略它)以验证handleChange
的更改将解决您的问题。
function areEqual(prevProps, nextProps) {
return (
prevProps.value === nextProps.value &&
prevProps.handleChange === nextProps.handleChange
);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.