使用带有钩子的 React.memo 来控制输入
Posted
技术标签:
【中文标题】使用带有钩子的 React.memo 来控制输入【英文标题】:Using React.memo with hooks for controlled inputs 【发布时间】:2019-10-12 15:11:28 【问题描述】:我正在通过自定义 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);
我在第一个输入中输入了一些文本。然后,当我切换到第二个输入并开始输入时,第一个输入会丢失值。就像表单没有呈现 LAST MEMOIZED 输入,而是呈现以前的版本。 我是 React 初学者,无法找出解决方案。有什么帮助吗?
【问题讨论】:
【参考方案1】:尝试使用 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
));
【讨论】:
非常感谢您的回复!根据您的建议,我最终阅读了一些相关的内容。我正在阅读此beware-react-setstate-is-asynchronous,但可能并非如此。 (或者是吗?)你能给我一些进一步阅读的链接吗? 这可能非常有用 [freecodecamp.org/news/… setState)【参考方案2】:您的 areEqual
方法转换为
仅当
value
更改时重新呈现我的输入。
但实际上,您的挂钩中的handleChange
函数也在发生变化。此外,您对两个输入使用相同的 handleChange
。因此,Input
“记住”只有上次value
发生变化的handleChange
,并且由于handleChange
通过关闭跟踪values
,它反过来“记住”values
已创建。
更改您的areEqual
方法(或完全省略它)以验证handleChange
的更改,将解决您的问题。
function areEqual(prevProps, nextProps)
return (
prevProps.value === nextProps.value &&
prevProps.handleChange === nextProps.handleChange
);
解决方案here的代码框
【讨论】:
"handleChange" 不是 Input 道具的一部分! “handleChange”是钩子的一部分。所以不可能有“prevProps.handleChange === nextProps.handleChange”。 @JoseMiguelOchoaInput
显然有一个 handleChange
属性。你试过我的解决方案了吗?
感谢您的回复。我现在明白你在说什么了。我试过你的解决方案。我应该提到我使用记忆输入,因为表单需要避免不必要的渲染。在我的真实项目形式中,我有很多选择和大量输入。如果我不记住输入和选择,它会使表单真正无响应(每个选择都使用 Apollo 从 Graphql 端点获取数据)。
当前实现中可能会出现许多细微的错误。如果 value
以外的任何属性发生更改,您的 Input 组件将不会重新渲染。现在可能会成功,但你以后永远不会知道。请记住这一点。
感谢您的建议!我会做的更一般,所以它可以接受更多的值。谢谢。以上是关于使用带有钩子的 React.memo 来控制输入的主要内容,如果未能解决你的问题,请参考以下文章