useRef для управления компонентом, который находится внутри дочернего компонента

#react-native #react-native-android #react-native-ios

#react-native #react-native-android #react-native-ios

Вопрос:

Я разрабатываю проект react-native.

Я создал пользовательский компонент, внутри которого я использую сторонний библиотечный компонент. Стороннему библиотечному компоненту требуется useRef перехват из моего кода, чтобы я мог управлять библиотечным компонентом.

     import React, {useRef} from 'react';
    ...
    const MyComponent = () => {
      const ref = useRef();
      return (
        <View>
          <Button
            title="OPEN 3rd party component"
            onPress={() => ref.current.open()}
          /> 
          <LibraryComponent
            ref={ref}
            ...
          />
        </View>)
}
 

Теперь у меня есть экран с именем MyScreen , который мне нужно отобразить MyComponent MyScreen , и управлять этим библиотечным компонентом MyScreen вместо MyComponent . Итак, я переработал MyComponent это (я удалил Button и изменил ref , чтобы быть передающим свойством):

 const MyComponent = ({ref}) => {
    
      return (
        <View>
          <LibraryComponent
            ref={ref}
            ...
          />
        </View>)
}
 

Затем в MyScreen :

 import React, {useRef} from 'react';
import MyComponent from '../components/MyComponent';

export const MyScreen = () => {
    const screenRef = useRef();
    ...

    return (
      <View style={styles.container}>
          <Button onPress=>{()=>screenRef.current.open()}/>
          <MyComponent ref={screenRef}>
          ...
      </View>
    )
   
}
 

Но я получаю предупреждающее сообщение: Function components cannot be give refs. Attempts to access this ref will fail. Did you mean to use React.ForwardRef() ?

Мои вопросы:

Как избавиться от этого предупреждения и MyScreen контролировать библиотечный компонент с помощью ссылочного крючка?

======== ОБНОВЛЕНИЕ =======

Я изменил имя свойства в MyComponent from ref на innerRef , как предложил @Rishabh Anand. Предупреждение исчезло.

 const MyComponent = ({innerRef}) => {
  ...
}
 

MyScreen теперь:

   export const MyScreen = () => {
        const screenRef = useRef();
        ...
    
        return (
          <View style={styles.container}>
              <Button onPress=>{()=>screenRef.current.open()}/>
              <MyComponent innerRef={screenRef}>
              ...
          </View>
        )
       
    }
 

Но теперь возникает новая проблема: когда я нажимаю на Button of MyScreen , приложение завершает работу с ошибкой undefined is not an object (evaluating screenRef.current.open) . Кажется screenRef.current null , что вместо компонента библиотеки используется a. Почему?

Комментарии:

1. ref это ключевое слово в React, в основном каждый компонент будет иметь один и может быть установлен только для того, чтобы не передаваться дочернему компоненту. Если вы можете попробовать изменить имя из ref в MyScreen на что-то вроде innerRef , когда вы передаете prop в <MyComponent innerRef={screenRef} /> ?

2. @Rishabh, да, спасибо. Но теперь возникает новая проблема: когда я нажимаю на Button MyScreen, приложение завершает работу с ошибкой undefined is not an object (evaluating screenRef.current.open) . Кажется screenRef.current , что вместо библиотечного компонента содержит значение null. Вы знаете, почему?

Ответ №1:

Вы должны использовать React.forwardRef

Из документации: https://fr.reactjs.org/docs/forwarding-refs.html

 const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
));

const ref = React.createRef();
<FancyButton ref={ref}>Cliquez ici</FancyButton>;
 

После установки ссылки вы можете вызвать некоторую функцию внутри вашего дочернего компонента следующим образом:

 const FancyButton = React.forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    click: () => {
      onClick();
    },
  }));

  const onClick = () => {
    console.log('Clicked.');
  };

  return (
    <button onClick={onClick} className="FancyButton">
      {props.children}
    </button>
  );
});

const ref = React.createRef();
  <FancyButton ref={ref}>Cliquez ici</FancyButton>;
 

И вызов из вашего родительского компонента

ref.current.click()