Реактивные крючки и функциональный компонент ref - PullRequest
1 голос
/ 16 октября 2019
const Comp1 = forwardRef((props, ref) => {
    useImperativeHandle(ref, () => ({
    print: () => {
      console.log('comp1')
    }
  }), []);
  return <div>comp1</div>
});

const Comp2 = () => <div>comp2</div>;

const App = () => {
  const ref1 = useRef(null);
  const ref2 = useRef(null);

  useEffect(() => {
    console.log(ref1); // prints ref1 with the expected current  
    console.log(ref2); // prints ref2 with current: null
  })
  return <div><Comp1 ref={ref1}/><Comp2 ref={ref2}/></div>
}
  1. В чем разница между ссылками Comp1 и Comp2?
  2. Почему я должен использовать forwardRef вместе с useImperativeHandle, чтобы фактически получить ссылку на Comp1?

https://codepen.io/benma/pen/mddEWjP?editors=1112

Ответы [ 2 ]

2 голосов
/ 16 октября 2019

Документация React гласит:

Вы не можете использовать атрибут ref на компонентах функций, потому что у них нет экземпляров. ( больше )

Это означает, что вы не можете привязать свои ссылки к функциональным компонентам. Вот почему ваш ref2.current равен null. Если вы хотите привязать ref к компоненту, вам нужно использовать компоненты класса. Ваш ref1 не является ссылкой на компонент Comp1. На самом деле он содержит объект, который вы передали в useImperativeHandle hook. то есть он содержит следующий объект:

{
    print: () => {
      console.log('comp1')
    }
}

Вы должны использовать forwardRef с функциональными компонентами, если вы хотите связать вашу ссылку с каким-либо элементом HTML или компонентом класса, который визуализирует ваш компонент. Или вы можете связать ваш ref с каким-либо объектом с помощью useImperativeHandle hook.

UPDATE

Использование useImperativeHandle аналогично добавлению методов к вашему. Компонент класса:

class Comp1 extends React.Component {
    print() {
        console.log('comp1');
    }

    render() {
        return (<div>comp1</div>)
    }
}

совпадает с

const Comp1 = forwardRef((props, ref) => {
    useImperativeHandle(ref, () => ({
    print: () => {
      console.log('comp1')
    }
  }), []);
  return <div>comp1</div>
});

Вы спросили в комментарии:

Итак, после перехода кловушки (и все же избегать использования классов), единственный способ использовать ref - это использовать useImperativeHandle (и фактически использовать «поддельный» ref)? Это хорошая практика?

Ответ: Использование useImperativeHandle является такой же плохой практикой, как и вызов методов дочерних компонентов при помощи ссылок в компонентах класса. React doc говорит, что вы должны избегать вызова методов дочерних компонентов по ссылкам, вы должны избегать использования useImperativeHandle. Кроме того, вы должны избегать использования ссылок, где вы можете делать вещи без них.

1 голос
/ 16 октября 2019

Я постараюсь ответить на вопрос 2

  • useImperativeHandle описал, что синтаксис ссылочного вызова будет с некоторыми настраиваемыми методами значения экземпляра, доступного для родителя.

  • forwardRef помогает пересылать ссылку через компонент высшего порядка для ссылки на внутренний узел DOM.

, когда вы попытаетесь сфокусироваться: ref1.current.focus(), дочерний ввод будет сфокусированным, а не компонентом более высокого порядка, который оборачивает дочерний ввод.

Посмотрите на простой пример, связанный с ответом, с помощью метода setValue useImperativeHandle и прямого ввода в ChildInput: https://codesandbox.io/s/react-hook-useimperativehandle-huktt

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...