[英]Using Controller component of react-hook-form doesn't allow custom Antd Select to show label
[英]Custom React component doesn't show input length when used with react-hook-form
具有以下 Textarea 組件,它是為了可重用而構建的,它是一個基本的 textarea,具有一個 maxlength 道具,可以指定最大輸入長度,它還顯示當前輸入長度,格式為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
傳播到 textarea 道具時,這可能會破壞您的自定義處理程序。
相反,您應該從 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>
);
}
);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.