将 React.memo 与钩子一起用于受控输入
Using React.memo with hooks for controlled inputs
我正在通过自定义 React 挂钩提供一些表单功能。这个钩子有一些类似于 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
};
}
表格如下:
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>
);
}
记忆组件是下一个:
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);
我在第一个输入框中输入了一些文本。然后,当我切换到第二个输入并开始输入时,第一个输入失去了价值。就像表单没有呈现最后的 MEMOIZED 输入,而是呈现以前的版本。
我是 React 初学者,无法找出解决方案。有什么帮助吗?
尝试使用 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
}));
}
您的 areEqual
方法转换为
Re-render my Input ONLY when the value
changes.
但实际上,您的 handleChange
钩子函数也在发生变化。此外,您对两个输入使用相同的 handleChange
。因此,Input
"remembers" 只有上次 value
的 handleChange
发生了变化,并且由于 handleChange
通过闭包跟踪 values
,它 in-turn "remembers" values
创建时。
更改 areEqual
方法(或完全忽略它)以验证 handleChange
中的更改将解决您的问题。
function areEqual(prevProps, nextProps) {
return (
prevProps.value === nextProps.value &&
prevProps.handleChange === nextProps.handleChange
);
}
一个解决方案的codesandbox here
我正在通过自定义 React 挂钩提供一些表单功能。这个钩子有一些类似于 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
};
}
表格如下:
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>
);
}
记忆组件是下一个:
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);
我在第一个输入框中输入了一些文本。然后,当我切换到第二个输入并开始输入时,第一个输入失去了价值。就像表单没有呈现最后的 MEMOIZED 输入,而是呈现以前的版本。 我是 React 初学者,无法找出解决方案。有什么帮助吗?
尝试使用 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
}));
}
您的 areEqual
方法转换为
Re-render my Input ONLY when the
value
changes.
但实际上,您的 handleChange
钩子函数也在发生变化。此外,您对两个输入使用相同的 handleChange
。因此,Input
"remembers" 只有上次 value
的 handleChange
发生了变化,并且由于 handleChange
通过闭包跟踪 values
,它 in-turn "remembers" values
创建时。
更改 areEqual
方法(或完全忽略它)以验证 handleChange
中的更改将解决您的问题。
function areEqual(prevProps, nextProps) {
return (
prevProps.value === nextProps.value &&
prevProps.handleChange === nextProps.handleChange
);
}
一个解决方案的codesandbox here