与 react-hook-form 一起使用时,自定义 React 组件不显示输入长度
Custom React component doesn't show input length when used with react-hook-form
有以下Textarea组件,它是为了可重用而构建的,它是一个基本的textarea,有一个maxlength props,它可以指定最大输入长度,它还显示当前输入长度,在格式 current input length/max length
.
它作为一个单独的组件工作正常,问题是当它必须与 react-hook-form 一起使用时,当前输入长度没有更新。
这是 Textarea 组件:
import React, { useState, useEffect } from 'react';
import useTextareaController from './use-textarea-controller';
export interface TexareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
maxLength?: number;
id: string;
}
export const Textarea = React.forwardRef(
(
{ id, maxLength = 200, ...props }: TexareaProps,
ref: React.ForwardedRef<HTMLTextAreaElement>
) => {
const { textareaRefSetter } = useTextareaController(ref);
const [count, setCount] = useState(0);
useEffect(() => {
const refElement = document.getElementById(id) as HTMLTextAreaElement;
if (refElement) {
setCount(refElement.value.length);
}
}, [id]);
return (
<div>
<div>
{count}/{maxLength}
</div>
<textarea
id={id}
ref={textareaRefSetter}
onChange={(event) => setCount(event.target.value.length)}
maxLength={maxLength}
{...props}
></textarea>
</div>
);
}
);
export default Textarea;
它使用了来自另一个钩子的 useTextareaController,这里是代码:
import React, { useRef } from 'react';
/**
* Utility function which registers and then removes event listeners for specified elements.
* @param el Reference of element for which to register event
* @param eventType native event type
* @param onEventCallback callback to be bound to event
*/
/**
* Controls the appearance of Button / Icon that is assigned to the reference,
* using the visibility property.
*
* This implementation has been made in the effort of
* keeping the input uncontrolled whenever it is possible.
*
* @See https://react-hook-form.com/api/useform/register/
* @param forwardedInputRef forwarded reference to be set by this hook
* @param disabled clear button / icon won't appear if it is false
* @returns referenceSetter function to assign the inner input element to the forwarded reference
* and the reference of the clear button / icon
*/
export const useTextareaController = (
forwardedInputRef: React.ForwardedRef<HTMLTextAreaElement>
) => {
const innerInputRef = useRef<HTMLTextAreaElement>();
// Both the inner reference and the forwarded reference should be set
const textareaRefSetter = (el: HTMLTextAreaElement) => {
innerInputRef.current = el;
if (!forwardedInputRef) return;
if (typeof forwardedInputRef === 'function') {
forwardedInputRef(el);
}
if (typeof forwardedInputRef === 'object') {
forwardedInputRef.current = el;
}
};
return { textareaRefSetter };
};
export default useTextareaController;
这是一个模态组件,里面有 Textarea 并使用 react-hook-form 进行验证:
import { yupResolver } from '@hookform/resolvers/yup';
import { useForm } from 'react-hook-form';
import * as yup from 'yup';
import { Modal, Textarea } from '../shared/ui-components';
const schema = yup.object().shape({
description: yup.string().required()
});
export interface Task {
description: string;
}
export interface MyModalProps {
title: string;
open: boolean;
toggle: () => void;
}
export function MyModal({ title, open, toggle }: MyModalProps) {
const emptyTask = { description: '' };
const { handleSubmit, reset, register } = useForm({
resolver: yupResolver(schema)
});
const onSubmit = (data: Task) => {
// send a POST request
toggle();
reset(emptyTask);
};
return (
<Modal title={title} open={open} onClose={toggle} onSubmit={handleSubmit(onSubmit)}>
<div>
<Textarea id='my-textarea' {...register('description')} />
</div>
</Modal>
);
}
export default MyModal;
有没有办法让当前输入长度与 react-hook-form 结合使用?
我想必须在 Textarea 组件中进行更改。
react-hook-form 提供了自己的 onChange
处理程序,它将作为 props
的一部分传递,当您将 props
传播到其中时,这可能会破坏您的自定义处理程序文本区域道具。
您应该改为从 props 中提取 onChange 并定义您自己的 onChange 回调,如果它被传入则调用它,而不是将其传播到您的 props 中。
export const Textarea = React.forwardRef(
(
{ id, maxLength = 200, onChange, ...props }: TexareaProps,
ref: React.ForwardedRef<HTMLTextAreaElement>
) => {
const { textareaRefSetter } = useTextareaController(ref);
const [count, setCount] = useState(0);
useEffect(() => {
const refElement = document.getElementById(id) as HTMLTextAreaElement;
if (refElement) {
setCount(refElement.value.length);
}
}, [id]);
const onChangeHandler = useCallback(
(event) => {
setCount(event.target.value.length);
onChange?.(event);
},
[setCount, onChange]
);
return (
<div>
<div>
{count}/{maxLength}
</div>
<textarea
id={id}
ref={textareaRefSetter}
onChange={onChangeHandler}
maxLength={maxLength}
{...props}
></textarea>
</div>
);
}
);
有以下Textarea组件,它是为了可重用而构建的,它是一个基本的textarea,有一个maxlength props,它可以指定最大输入长度,它还显示当前输入长度,在格式 current input length/max length
.
它作为一个单独的组件工作正常,问题是当它必须与 react-hook-form 一起使用时,当前输入长度没有更新。
这是 Textarea 组件:
import React, { useState, useEffect } from 'react';
import useTextareaController from './use-textarea-controller';
export interface TexareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
maxLength?: number;
id: string;
}
export const Textarea = React.forwardRef(
(
{ id, maxLength = 200, ...props }: TexareaProps,
ref: React.ForwardedRef<HTMLTextAreaElement>
) => {
const { textareaRefSetter } = useTextareaController(ref);
const [count, setCount] = useState(0);
useEffect(() => {
const refElement = document.getElementById(id) as HTMLTextAreaElement;
if (refElement) {
setCount(refElement.value.length);
}
}, [id]);
return (
<div>
<div>
{count}/{maxLength}
</div>
<textarea
id={id}
ref={textareaRefSetter}
onChange={(event) => setCount(event.target.value.length)}
maxLength={maxLength}
{...props}
></textarea>
</div>
);
}
);
export default Textarea;
它使用了来自另一个钩子的 useTextareaController,这里是代码:
import React, { useRef } from 'react';
/**
* Utility function which registers and then removes event listeners for specified elements.
* @param el Reference of element for which to register event
* @param eventType native event type
* @param onEventCallback callback to be bound to event
*/
/**
* Controls the appearance of Button / Icon that is assigned to the reference,
* using the visibility property.
*
* This implementation has been made in the effort of
* keeping the input uncontrolled whenever it is possible.
*
* @See https://react-hook-form.com/api/useform/register/
* @param forwardedInputRef forwarded reference to be set by this hook
* @param disabled clear button / icon won't appear if it is false
* @returns referenceSetter function to assign the inner input element to the forwarded reference
* and the reference of the clear button / icon
*/
export const useTextareaController = (
forwardedInputRef: React.ForwardedRef<HTMLTextAreaElement>
) => {
const innerInputRef = useRef<HTMLTextAreaElement>();
// Both the inner reference and the forwarded reference should be set
const textareaRefSetter = (el: HTMLTextAreaElement) => {
innerInputRef.current = el;
if (!forwardedInputRef) return;
if (typeof forwardedInputRef === 'function') {
forwardedInputRef(el);
}
if (typeof forwardedInputRef === 'object') {
forwardedInputRef.current = el;
}
};
return { textareaRefSetter };
};
export default useTextareaController;
这是一个模态组件,里面有 Textarea 并使用 react-hook-form 进行验证:
import { yupResolver } from '@hookform/resolvers/yup';
import { useForm } from 'react-hook-form';
import * as yup from 'yup';
import { Modal, Textarea } from '../shared/ui-components';
const schema = yup.object().shape({
description: yup.string().required()
});
export interface Task {
description: string;
}
export interface MyModalProps {
title: string;
open: boolean;
toggle: () => void;
}
export function MyModal({ title, open, toggle }: MyModalProps) {
const emptyTask = { description: '' };
const { handleSubmit, reset, register } = useForm({
resolver: yupResolver(schema)
});
const onSubmit = (data: Task) => {
// send a POST request
toggle();
reset(emptyTask);
};
return (
<Modal title={title} open={open} onClose={toggle} onSubmit={handleSubmit(onSubmit)}>
<div>
<Textarea id='my-textarea' {...register('description')} />
</div>
</Modal>
);
}
export default MyModal;
有没有办法让当前输入长度与 react-hook-form 结合使用?
我想必须在 Textarea 组件中进行更改。
react-hook-form 提供了自己的 onChange
处理程序,它将作为 props
的一部分传递,当您将 props
传播到其中时,这可能会破坏您的自定义处理程序文本区域道具。
您应该改为从 props 中提取 onChange 并定义您自己的 onChange 回调,如果它被传入则调用它,而不是将其传播到您的 props 中。
export const Textarea = React.forwardRef(
(
{ id, maxLength = 200, onChange, ...props }: TexareaProps,
ref: React.ForwardedRef<HTMLTextAreaElement>
) => {
const { textareaRefSetter } = useTextareaController(ref);
const [count, setCount] = useState(0);
useEffect(() => {
const refElement = document.getElementById(id) as HTMLTextAreaElement;
if (refElement) {
setCount(refElement.value.length);
}
}, [id]);
const onChangeHandler = useCallback(
(event) => {
setCount(event.target.value.length);
onChange?.(event);
},
[setCount, onChange]
);
return (
<div>
<div>
{count}/{maxLength}
</div>
<textarea
id={id}
ref={textareaRefSetter}
onChange={onChangeHandler}
maxLength={maxLength}
{...props}
></textarea>
</div>
);
}
);