Какой правильный тип для ссылки в React?

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

Репозиторий, который хранится, выглядит следующим образом:

ref={node => this.myRefToBePutInReduxGlobalStore = node}

Каков правильный propType для этого ref?

Ответ 1

Ответьте на конкретный вопрос, описанный в оригинальном сообщении

В примере с вопросом о OP, необходимо объявить не тип опоры ref, а материал, на который указывает ссылка, и который будет передан из Redx с использованием mapStateToProps. Тип поддержки для элемента DOM будет: myRefToBePutInReduxGlobalStore: PropTypes.instanceOf(Element) (если это элемент DOM). Хотя я бы:

  1. Переименуйте статику в myElementToBePutInReduxGlobalStore (это не ссылка как таковая)
  2. Избегайте хранения несериализуемых данных в хранилище с избыточностью
  3. Избегайте передачи элементов в подпорки, как объяснил инженер React Себ Маркбедж

Ответ на актуальный вопрос

В: Какой правильный тип для ссылки в React?

Пример использования:

function FancyInput({ inputRef }) {
    return (
        <div className="fancy">
            Fancy input
            <input ref={inputRef} />
        </div>
    )
}

FancyInput.propTypes = {
    inputRef: ???   // What is the correct prop type here?
}

function App() {
    const inputRef = React.useRef()
    useEffect(function focusWhenStuffChange() => {
        inputRef.current && inputRef.current.focus()
    }, [stuff])
    return <FancyInput inputRef={inputRef} />
}

Сегодня в реакции существуют два вида ссылок:

  1. Объект, который выглядит так: { current: [something] }, обычно создается React.createRef() вспомогательный или React.useRef() хук
  2. Функция обратного вызова, которая получит [something] в качестве аргумента (как в примере с OP)

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

Второй элемент довольно прост и требует следующего типа пропеллера: PropTypes.func.

Первый вариант менее очевиден, поскольку вы можете указать тип элемента, на который указывает ссылка.

TL; DR

Если вы ожидаете только собственные элементы DOM, такие как div или input, правильное определение будет следующим:

refProp: PropTypes.oneOfType([
    // Either a function
    PropTypes.func, 
    // Or the instance of a DOM native element (see the note about SSR)
    PropTypes.shape({ current: PropTypes.instanceOf(Element) })
])

Длинный ответ

ref может указывать на что-то еще, кроме элемента DOM.

Если вы хотите быть полностью гибким:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.any })
])

Вышеприведенное только что применяет форму объекта ref со свойством current. Это будет работать в любое время для любого вида реф. Для цели использования типа проп, который является способом выявления любых несоответствий при разработке, этого, вероятно, достаточно. Кажется очень маловероятным, что объект с формой { current: [any] } и переданный в refToForward опору, не будет действительным ссылочным номером.

Тем не менее, вы можете объявить, что ваш компонент не ожидает какого-либо реф, а только определенного типа, учитывая, для чего он нужен.

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


Если вы ожидаете только ссылку, указывающую на собственный элемент ввода, а не на какой-либо HTML Element:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(HTMLInputElement) })
])

Если вы ожидаете только ссылку, указывающую на компонент класса React:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.instanceOf(Component) })
])

Если вы ожидаете, что ссылка, указывающая на функциональный компонент с помощью useImperativeHandle, предоставит какой-то открытый метод:

refProp: PropTypes.oneOfType([
    PropTypes.func, 
    PropTypes.shape({ current: PropTypes.object })
])

Примечание: приведенный выше тип prop интересен тем, что он также охватывает компоненты реакции и собственные элементы DOM, поскольку все они наследуют базовый JavaScript Object


Не существует единственного хорошего способа объявить тип реквизита для ссылки, это зависит от использования. Если ваш реф указывает на что-то очень идентифицированное, возможно, стоит добавить определенный тип проп. В противном случае достаточно просто проверить общую форму.


Примечание о рендеринге на стороне сервера

Если ваш код должен выполняться на сервере, если вы уже не заполняете DOM-среду, Element или любой другой тип клиентской стороны будет undefined в NodeJS. Вы можете использовать следующую прокладку для его поддержки:

Element = typeof Element === 'undefined' ? function(){} : Element

На следующих страницах React Docs содержится более подробное описание того, как использовать ссылки, объектные и обратные вызовы, а также как использовать ловушку useRef

Ответ обновлен благодаря @Rahul Sagore, @Ferenk Kamras и @svnm

Ответ 2

Я проверяю только предпочтительный способ, и поскольку PropType.object не очень полезен, я использовал это:

PropTypes.shape({ current: PropTypes.instanceOf(Element) })

Ответ 3

Очень похоже на пост @Pandaiolo,

PropTypes.elementType был добавлен

forwardedRef: PropTypes.oneOfType([
  PropTypes.func,
  PropTypes.shape({ current: PropTypes.elementType })
]),

При использовании PropTypes> = 15.7.0 PropTypes.elementType был добавлен 10 февраля 2019 в этом PR