Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forwarding ref in a functional component with react-redux (v. 6.0.1)

I'm trying to use forwardRef in my functional component that is also using react-redux. My component looks like this:

const InfiniteTable = ({
  columns,
  url,
  data,
  stateKey,
  loading,
  loadMore,
  fetchData,
  customRecordParams,
  ...rest
}, ref) => {
  const [start, setStart] = useState(0);
  const tableRef = React.createRef();

  console.log(rest);

  let dataSource = data;
  if (customRecordParams) dataSource = _.map(dataSource, customRecordParams);
  if (dataSource.length > FETCH_LIMIT)
    dataSource = _.slice(dataSource, 0, start + FETCH_LIMIT);

  useEffect(() => setupScroll(setStart, tableRef), []);
  useEffect(() => {
    if (loadMore) fetchData(url, stateKey, { start });
  }, [start, loadMore]);

  useImperativeHandle(ref, () => ({
    handleSearch: term => console.log(term),
    handleReset: () => console.log("reset")
  }));

  return (
    <Table
      columns={columns}
      dataSource={dataSource}
      pagination={false}
      showHeader
      loading={loading}
    />
  );
}; 

const mapStateToProps = (state, ownProps) => ({
  data: Object.values(state[ownProps.stateKey].data),
  loading: state[ownProps.stateKey].isFetching,
  loadMore: state[ownProps.stateKey].loadMore
});

export default connect(
  mapStateToProps,
  { fetchData },
  null,
  { forwardRef: true }
)(InfiniteTable);

However I'm getting this error when trying to use my component with a ref prop:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

What am I doing wrong?

like image 537
InesM Avatar asked Mar 15 '19 10:03

InesM


People also ask

How do you pass ref to the functional component?

To create a ref in a functional component we use the useRef() hook which returns a mutable object with a . current property set to the initialValue we passed to the hook. This returned object will persist for the full lifetime of the component. Thus, throughout all of its re-rendering and until it unmounts.

Can Ref be used in functional component?

You may not use the ref attribute on function components because they don't have instances.

How do you pass a ref to a forwardRef?

The only way to pass a ref to a function component is using forwardRef. When using forwardRef, you can simply pass the ref to a DOM element, so the parent can access it like in example 1, or you could create an object with fields and methods using the useImperativeHandle hook, which would be similar to eample 2.

How do you pass ref as props in React?

React passes the ref to the (props, ref) => ... function inside forwardRef as a second argument. We forward this ref argument down to <button ref={ref}> by specifying it as a JSX attribute. When the ref is attached, ref.


1 Answers

InfiniteTable signature is incorrect, it's legacy context that is received as second parameter in functional components, not ref. In order to receive ref object to use it with useImperativeHandle, a component should be wrapped with React.forwardRef.

As the reference states,

useImperativeHandle customizes the instance value that is exposed to parent components when using ref. As always, imperative code using refs should be avoided in most cases. useImperativeHandle should be used with forwardRef

It should be:

const InfiniteTable = forwardRef((props, ref) => { ... });

export default connect(
  mapStateToProps,
  { fetchData },
  null,
  { forwardRef: true }
)(InfiniteTable);
like image 93
Estus Flask Avatar answered Nov 02 '22 21:11

Estus Flask