I have two components. A parent and a child.
Inside the parent component I have a button. If the user clicks on that button I want to do a ScrollIntoView to another button inside the child component.
I guess I want to define a reference to the childs button a so that I inside the parent button onClick can do a:
ref.scrollIntoView({block: 'end', behavior: 'smooth'});
that will scroll to the button in the child component.
Here is a minified example:
import React, {useRef} from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = props => {
const childReference = useRef(null);
const onClick = () => {
childReference.scrollIntoView({block: 'end', behavior: 'smooth'});
}
return (
<>
<...some other components>
<Button onClick={onClick}>Click me to be forwarded</Button>
<ChildComponent ref={childReference}/>
</>
);
};
import React from 'react';
const ChildComponent = (props, ref) => {
const { name, value, description } = props;
return (
<...some other components>
<Button ref={ref}>You should be forwarded to me</Button>
);
};
ChildComponent.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.number,
description: PropTypes.string,
};
ChildComponent.defaultProps = {
value: 0,
description: '',
};
export default React.forwardRef(ChildComponent);
I know the above code doesn't work, it was just to illustrate what I am trying to achieve.
I have really tried every other solution I have been able to find by Googling and they all seem so easy, but none of them seem to work for my use case. I have tried using forwardRef as well, but that also doesn't fix it for me.
I guess I was a little vague on what's not working. I've been getting a lot of different error messages with the implementation.
The following is one of them:
Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
Okay. I thought I'd assemble the pieces here with the solution provided by @Vencovsky.
This is the full implementation with the two example components seen in the question:
import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = props => {
const childReference = useRef(null);
const scrollIntoView = () => {
childReference.current.scrollIntoView({block: 'center', inline: 'center', behavior: 'smooth'});
}
return (
<>
<...some other component>
<Button onClick={scrollIntoView}>Click me to be forwarded</Button>
<ChildComponent ref={childReference}
</>
);
};
export default ParentComponent;
import React, {forwardRef} from 'react';
import PropTypes from 'prop-types';
const ChildComponent = forwardRef((props, ref) => {
const { name, value, description } = props;
return(
<>
<...some other components>
<Button ref={ref}>You should be forwarded to me</Button>
</>
);
});
ChildComponent.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.number,
description: PropTypes.string,
};
ChildComponent.defaultProps = {
value: 0,
description: '',
};
export default ChildComponent;
The forwardRef hooks allows React users to pass refs to child components. The ref can be created and referenced with useRef or createRef and then passed in a parent component. Using forwardRef instead of useRef is useful when a ref needs to be accessed in a parent component.
To pass data from a child component to its parent, we can call a parent function from the child component with arguments. The parent function can be passed down to the child as a prop, and the function arguments are the data that the parent will receive.
Scroll to an Element With the React Refs (References): The most simple way is to use ref to store the reference of the element that you want to scroll to. And call myRef. current. scrollIntoView() to scroll it into the view.
To pass an onChange event handler to a child component in React: Define the event handler function in the parent component. Pass it as a prop to the child component, e.g. <Child handleChange={handleChange} /> . Set it to the onChange prop on the input field in the child.
I guess you are doing something like
const ChildComponent = (props, ref) => { ... }
ChildComponent.propTypes = { ... }
export default React.forwardRef(ChildComponent)
But what you need to do is pass propTypes
after React.forwardRef
, like so:
const ChildComponent = (props, ref) => { ... }
const ForwardComponent = React.forwardRef(ChildComponent)
ForwardComponent.propTypes = { ... }
export default ForwardComponent
A better way to do it would be like
// using forwarRef
const ChildComponent = React.forwarRef((props, ref) => {
const { name, value, description } = props;
return (
<...some other components>
<Button ref={ref}>You should be forwarded to me</Button>
);
});
Then you wouldn't need to change propTypes
and create another component.
As your Edit, I can see that you forgot to use React.forwardRef
.
You should add
export default React.forwardRef(ChildComponent)
To your ChildComponent
file (export it with forwardRef).
What is not working? Are you getting an error? You should explain better what is going on, but I will try to guess.
There is somethings that can make it not work.
ref.current.foo
instead of ref.foo
It seems that your button is also a custom component. Are you sure the ref is being passed to the html button element inside there?
React.forwardRef
. e.g. export default React.forwardRef(ChildComponent)
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