Невозможно сфокусировать ввод в реакции

Я пытаюсь сфокусировать поле ввода, которое находится внутри вкладки Antd, всякий раз, когда пользователь щелкает эту вкладку (т. е. всякий раз, когда поле ввода отображается). Для этого я использую хук useImperativeHandle.

родительский компонент


const Parent=()=>{
const threadRef=useRef()
() => {
  const onTabChange = activeKey => {
    if (activeKey === 1 && chatThreadRef.current) {
      chatThreadRef.current.focusInput()
    }
  }
  return (
    <Tabs
      items = {[
        { label: 'tab 1', key: 0, children: <>tab 1</> },
        { label: 'tab 2', key: 1, children: <ChildComponent/> },
      ]}
      onChange = {onTabChange}
    />
  )
}
}

Дочерний компонент

const ChildComponent = forwardRed((props,ref) => {
  const [focusableElements, setFocusableElements] = useState([])
  const wrapperRef = useRef(null)
  useEffect(() => {
    const messageInput = wrapperRef.current.querySelector('input')
    setFocusableElements(messageInput)
  }, [])

  useImperativeHandle(ref, () => ({
    focusInput: () => {
      console.info(focusableElements[0])
      focusableElements[0].value = '1'
      focusableElements[0].focus()
    },
  }))
  return (
    <div ref = {wrapperRef}>
      <Input className = "input" />
    </div>
  )
})

Всякий раз, когда focusInput вызывается в родительском компоненте, оператор console.info(focusableElements[0]) в коде печатает элемент ввода, и я также могу установить значение для ввода, но он не фокусируется.

вы не передаете ссылку в ChildComponent (и у вас есть опечатка в forwardRef). Кроме того, почему вы используете ref, а затем запрашиваете его? Просто примените ссылку к фактическому элементу, на который вы хотите ссылаться. Вы также можете просто применить свойство autoFocus к входу.

pilchard 17.04.2023 11:15
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
113
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Похоже, в вашем коде может быть небольшая ошибка. Вместо того, чтобы устанавливать для свойства value элемента ввода focusableElements[0] значение '1' перед вызовом focus(), вы должны установить его после вызова focus().

Попробуйте изменить функцию focusInput в дочернем компоненте на:

focusInput: () => {
  console.info(focusableElements[0])
  focusableElements[0].focus()
  focusableElements[0].value = '1'
},

Таким образом, элемент ввода будет сначала сфокусирован, а затем его значение будет установлено на «1».

Добавьте console.info("onTabChange in parent") в onTabChange в родительский компонент.

Вы должны увидеть, что это было вызвано до вашего console.info(focusableElements[0]), а не снова, не после.

По 2 причинам:

  • Вы вставляете setFocusableElements(messageInput) в useEffect, потому что ref.current нужно отрендерить. Но он будет называться после onTabChange, который в первую очередь вызвал все это.
  • useEffect вызовет setFocusableElements, что вызовет повторную визуализацию дочернего элемента. useImperativeHandle будет обновлен при этом повторном рендеринге с FocusableElements, но изменение useImperativeHandle не приведет к повторному рендерингу родителя с использованием ссылки.

Решение :

focus() должен стоять в useEffect.

Но опять же, если вы поместите этот вызов в родителя, он не будет работать. Дочерний повторный рендеринг не будет запускаться, если родительский повторный рендеринг. Лучше всего, если вы сосредоточите внимание непосредственно на ребенке.

У нас нет здесь контекста о том, почему вы строите это таким образом, но если вам абсолютно необходимо, чтобы фокус контролировался родителем, вместо этого используйте логические реквизиты:

// In the parent component :
const parent = () => {
   const [willFocus, setWillFocus] = useState(false);
   const onTabChange = activeKey => {
      if (activeKey === 1 && chatThreadRef.current) {
        setWillFocus(true)
      }
   }
   return <Child willFocus = {willFocus} />
// In the child component :
const parent = ({willFocus}) => {
   const ref = useRef(null);
   useEffect(() => {
      willFocus && ref.current.focus();
   }, [willFocus]);

   return <input ref = {ref} />
Ответ принят как подходящий

исправил это, добавив время ожидания, подобное этому

  useImperativeHandle(ref, () => ({
    focusInput: () => {
      setTimeout(()=>{
      focusableElements[0].value = '1'
      focusableElements[0].focus()
    },100)
    },
  }))

Другие вопросы по теме