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?
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.
You may not use the ref attribute on function components because they don't have instances.
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.
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With