HarshvardhanSharma
HarshvardhanSharma

Reputation: 786

Forwarding Refs: forwardedRef is always null

I have an ant design Table component that I want ref to be attached to.

I want to be able to use the tableRef in HOC withCustomPagination's lifecycle componentDidUpdate method.

Following the React Docs Forwarding Refs, that I could not clearly comprehend. I could cook up the following code:

App.js

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

class App extends React.Component {
  render() {
    const tableRef = React.createRef();
    return (
      <WrappedTable ref={tableRef} />
    )
  }
}

Table.js

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

class Table extends React.Component {
  constructor(props) {
    super(props); 
  }

  render() {
    <TableContainer ref={this.props.forwardedRef} />
  }
}

const WrappedTable = withCustomPagination(Table);
export default WrappedTable;

withCustomPagination.js

import CustomPagination from 'path/to/file';

const withCustomPagination = tableRef => Component => {
  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() {
      const { forwardedRef } = this.props;
      return (
        <Component {...this.state} ref={forwardedRef} />
        <CustomPagination />
      )
    }
  }
  return React.forwardRef((props, ref) => {
    return <WithCustomPagination {...props} forwardedRef={ref} />;
  });
}

export default withCustomPagination;

After debugging, I find that forwardedRef is always null.

Debug session screenshot

Upvotes: 5

Views: 5532

Answers (2)

Sergio Escudero
Sergio Escudero

Reputation: 1894

Your issue is happening in your HOC:

                              here
const withCustomPagination = tableRef => Component => {

You need to remove that parameter. The way to access to the ref prop is simply in your componentDidUpdate method like forwardedRef prop e.g:

import CustomPagination from 'path/to/file';

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

    componentDidUpdate() {
      //You got the ref here
      console.log(forwardedRef.current)
    }

    render() {
      const { forwardedRef } = this.props;
      return (
        <Component {...this.state} ref={forwardedRef} />
        <CustomPagination />
      )
    }
  }
  return React.forwardRef((props, ref) => {
    return <WithCustomPagination {...props} forwardedRef={ref} />;
  });
}

export default withCustomPagination;

Also somethings to have in account are:

You should not create the ref in the render method because this method is raised every time you set a state. I recommend you to do it in the constructor:

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

class App extends React.Component {
  constructor(){
    super();
    this.reference = React.createRef();
  }
  render() {
    return (
      <WrappedTable ref={this.reference} />
    )
  }
}

Also in you HOC render only one child or use React.Fragment. Besides do not forget the send the rest properties:

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

    componentDidUpdate() {
      //You got the ref here
      console.log(forwardedRef.current)
    }

    render() {
      // Do not forget to send the rest of properties here like:
      const { forwardedRef, ...rest } = this.props;
      return (
        <React.Fragment>
          <Component {...this.state} ref={forwardedRef} {...rest} />
          <CustomPagination />
        </React.Fragment>
      )
    }
  }
  return React.forwardRef((props, ref) => {
    return <WithCustomPagination {...props} forwardedRef={ref} />;
  });
}

export default withCustomPagination;

EDIT:

Add the reference of the ref prop

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

class Table extends React.Component {
  constructor(props) {
    super(props); 
    this.reference = React.createRef();
  }

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

const WrappedTable = withCustomPagination(Table);
export default WrappedTable;

Upvotes: 2

HarshvardhanSharma
HarshvardhanSharma

Reputation: 786

To access the tableRef in HOC withCustomPagination, I removed const tableRef = React.createRef() from App.js and the corresponding ref = {tableRef} lines. I pass tableRef to HOC, curried, withCustomPagination(tableRef)(NewGiftCardTable). I also removed all the Forwarding Refs logic in HOC, this I did because I needed access to tableRef only in HOC and not in App.js.

Added above removed lines to Table.js:

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

const tableRef = React.createRef(); 

class Table extends React.Component {
  constructor(props) {
    super(props); 
  }

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

const WrappedTable = withCustomPagination(tableRef)(Table);
export default WrappedTable;

Upvotes: 0

Related Questions