簡體   English   中英

與 react-hook-form 一起使用時,自定義 React 組件不顯示輸入長度

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM