I have a component that handles user authentication and displays a login form if needed, otherwise just displays the children.
function AuthWrapper({children}){
let [auth, setAuth] = React.useState(null);
React.useEffect(()=>{
// Do stuff to check or change state
}, []);
let component = (<>Loading...</>);
if(auth){
component = (<>{children}</>);
}
return component;
}
Then I use it in another component where I need to access stuff in the DOM with a ref
.
function App(props) {
let inputRef = React.useRef();
React.useEffect(()=>{
console.log('currentRef', inputRef.current);
}, []);
return (
<AuthWrapper>
<input placeholder='Enter your name' ref={inputRef} />
</AuthWrapper>
);
}
Problem is, obviously, there’s nothing in the DOM to reference at the time the useEffect
is called because the AuthWrapper
hasn’t rendered the children yet. Therefore, inputRef.current
is always undefined.
I kind of understand the problem, but every solution I’ve tried has either failed or just felt really gross and hacky. What are some best practices or clean solutions for setting my reference to a DOM element that doesn’t render immediately, and then accessing it once it does render?
Here’s an online code playground demo: https://playcode.io/1769946
2
Answers
Replacing the
useEffect
with auseCallback
and then using the callback to set the reference was the correct solution, and appears to be best practice when dealing with references in general.Something like this...
is better written as
The post that cleared it up for me was here.
By default React does not let a component access the DOM nodes of other components. You will have to go through the
parent
first (in this case that isAuthWrapper
). You give thereference
(s) to theparent
then theparent
makes the attachment for you to the specificchild
(ren). For example:Now
AuthWrapper
i.e. theparent
is solely responsible for how it lets external routines access it’schild
(ren). This design principle is part of a general attempt to have complete component encapsulation. We will now rewriteAuthWrapper
as follows:If there will be more than one
child
, you will use multipleref
s. I would recommend usinguseImperativeHandle
hook.