【问题标题】:Custom React component doesn't show input length when used with react-hook-form与 react-hook-form 一起使用时,自定义 React 组件不显示输入长度
【发布时间】:2022-01-03 16:40:58
【问题描述】:

具有以下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 组件中进行更改。

【问题讨论】:

    标签: javascript reactjs typescript react-hooks react-hook-form


    【解决方案1】:

    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>
        );
      }
    );
    

    【讨论】:

      猜你喜欢
      • 2022-10-16
      • 2022-11-17
      • 1970-01-01
      • 2021-10-20
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 2021-09-16
      相关资源
      最近更新 更多