Forwarding ref in a functional component with reac

2019-07-08 19:35发布

问题:

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?

回答1:

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);