Используйте ref в компонентах более высокого порядка

У меня есть компонент Table, к которому я хочу подключить ref.

Использование: Table.js

class Table extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rows: 1,
      dataLength: props.dataLength,
    }
    this.tableRef = React.createRef(); 
  }

  componentDidUpdate() {
    //using ref
    this.tableRef.current ..... //logic using ref
    this.state.rows ..... //some logic
  }

  render() {
    <TableContainer ref = {this.tableRef} />
    <CustomPagination />
  }
}

Это работает нормально, но теперь мои требования изменились, и я хочу повторно использовать компонент Table с разбивкой на страницы, применяемой ко всем таблицам в моем приложении. Решил сделать HOC withCustomPagination.

Использование: withCustomPagination.js HOC

import CustomPagination from 'path/to/file';

const withCustomPagination = tableRef => Component => {
  return class WithCustomPagination extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        rows: 1,
        dataLength: props.dataLength,
      }
    }

    componentDidUpdate() {
      tableRef.current.state ..... //logic using ref, Error for this line
      this.state.rows ..... //some logic
    }

    render() {
      return (
        <Component {...state} />
        <CustomPagination />
      )
    }
  }
}

export default withCustomPagination;

Новый Table.js:

import withCustomPagination from '/path/to/file';

const ref = React.createRef();

const Table = props => (
  <TableContainer ref = {ref} />
);

const WrappedTable = withCustomPagination(ref)(Table);

HOC withCustomPagination возвращает класс WithCustomPagination, который имеет метод жизненного цикла componentDidUpdate, который использует ссылку на таблицу в логике. Поэтому я пытаюсь передать ref, созданный в Table.js, в качестве аргумента для withCustomPagination, т.е. каррированный с помощью компонента без сохранения состояния ref и Table.

Это использование ref неверно, и я получаю сообщение об ошибке: TypeError: Cannot read property 'state' of null.

Я пробовал использовать Пересылка ссылок, но не смог.

Как передать таблицу ref в withCustomPagination и использовать ее в HOC?

Поведение ключевого слова "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) для оценки ваших знаний,...
7
0
9 629
3

Ответы 3

Либо реструктурируйте свой код, чтобы не использовать для этого HOC, либо попробуйте использовать React.forwardRef:

Refs Aren’t Passed Through

While the convention for higher-order components is to pass through all props to the wrapped component, this does not work for refs. That’s because ref is not really a prop — like key, it’s handled specially by React. If you add a ref to an element whose component is the result of a HOC, the ref refers to an instance of the outermost container component, not the wrapped component.

The solution for this problem is to use the React.forwardRef API (introduced with React 16.3). Learn more about it in the forwarding refs section.

через Компоненты высшего порядка: ссылки не проходят

В раздел переадресации ссылок есть примеры кода, которые вы могли бы использовать для передачи refs вниз, но попытка поднять их в вашем случае не удастся:

Warning: Stateless function components cannot be given refs. Attempts to access this ref will fail.

В проекте мы использовали другой подход. Есть компонент EnhancedTable, который обрабатывает всю логику разбиения на страницы и сам по себе имеет компонент «тупой таблицы» и компонент разбивки на страницы. Он работает довольно хорошо, но это означает, что вам придется сверлить реквизиты (или использовать библиотеку хранилища, такую ​​как Redux или Mobx) и добавлять новые, которые будут обрабатывать параметры разбивки на страницы. Это приведет к некоторому рефакторингу использования Table, и вам придется быть более точным, но я бы воспринял это как благо, а не как препятствие.

В этом случае вы можете использовать useImperativeHandle

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

Вот мой пример Hoc:

import React from 'react';
import { View } from 'react-native';

export function CommonHoc(WrappedComponent) {

    const component = class extends React.Component {

         componentDidMount() {
           this.refs.myComponent.showAlert();

        }

        render() {
            return (
                <>
                    <WrappedComponent
                        ref='myComponent'
                        {...this.state}
                        {...this.props}
                    />
                </>
            );
        }
    };
    return component;
}

и это мой компонент без состояния

const HomeController=(props,ref)=> {

    useImperativeHandle(ref, () => ({

        showAlert() {
            alert("called");
        },
    }));

    return (
        <Text>home</Text>
    );
};
export default CommonHoc(forwardRef(HomeController));

Не могли бы вы предоставить обновленный ответ для нового решения на основе React.createRef ().

XPD 12.11.2019 10:11

Мне удалось решить аналогичную проблему, которая привела меня к этой теме, без использования forwardRef или useImperativeHandle.

Создав ссылку на более высоком уровне и передав ее в компоненты и подкомпоненты, которые мне нужно было действовать с помощью ссылки.

/** Parent Component has access to ref and functions that act on ref **/

import { useRef } from 'react';
const formRef = useRef(); // ref will have dom elements need accessing

const onClickFunction=()=>{ //sample function acts on ref
  var inputs = formRef.current.querySelectorAll('input')
 /* Act on ref here via onClick function, etc  has access to dom elements 
  in child component and childs child components */
 };
 return(
 <ComponentGetsAttachedRef formRef = {formRef} /> 
 //^ref sent down to component and its children
 <ComponentNeedingRef onClickFunction = {onClickFunction}/>
 //^function with access to ref sent down to component
 )

/** Child component needs to act on ref**/

export const ComponentNeedingRef = ({ onClickFunction}) =>{
 return(
  <button onClick = {onClickFunction}>
 )
}

/* Child component recieves ref and passes it down */

export const ComponentGetsAttachedRef = ({ formRef}) =>{
//ref comes in as prop gets attached to props or utilized internally

 return (
 <ChildsChildComponent formRef = {formRef}/> //sub component passed ref down
 )

}

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