React Hooks: Why is .current null for useRef Hook?
Solution 1
Ref.current
is null because the ref is not set till after the function returns and the content is rendered. The useEffect hook fires every time the value of contents of the array passed to it changes. By passing observed
in the array and by passing a callback that logs observed
to the console, the useEffect hook can be leveraged to accomplish your task.
useEffect(() => {
console.log(observed.current);
}, [observed]);
Edit: This only works on the first render as changes to a ref do not trigger re-renders. But the general statement about useEffect still holds. If you want to observe changes to a ref of a dom element, you can use a callback as ref.
<div
ref={el => { console.log(el); observed.current = el; }} // or setState(el)
className="App"
>
Solution 2
This is what I ended up doing since calling useEffect
on rlvRef
did not capture all events.
const rlvRef = useRef()
const [refVisible, setRefVisible] = useState(false)
useEffect(() => {
if (!refVisible) {
return
}
// detected rendering
}, refVisible)
return (
<RecyclerListView
ref={el => { rlvRef.current = el; setRefVisible(!!el); }}
...
/>
)
Xen_mar
Updated on March 22, 2021Comments
-
Xen_mar about 3 years
I have a simple example of a component:
function App() { const observed = useRef(null); console.log(observed.current); return ( <div ref={observed} className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
I would expect that
observed.current
would be of type element and current would not be empty but the div element with all its properties. My understanding would be:- The ref is initialised with a value of null
- Null is overwritten by the ref
But as it turns out,
.current
remains empty. This is bad since I want to pass observed to a function that expects an argument of type Element. -
Xen_mar almost 5 yearsGreat thanks! I am quite know to Hooks but for a functional component I would assume that the whole function is the "render function". Do you may have a reference of things I can and can't do in a render function?
-
Xen_mar almost 5 yearsGreat thanks! I am quite know to Hooks but for a functional component I would assume that the whole function is the "render function". Do you may have a reference of things I can and can't do in a render function?
-
James almost 5 years"You have to check for the value inside a
useEffect
hook" - this statement is not strictly true, I could have a memoised callback function that that can access a ref. The main point is the ref is null because the UI hasn't actually rendered yet,useEffect
works here becauseuseEffect
it's the equivalent tocomponentDidMount
and a few other hooks that run after the component has rendered. -
Avin Kavish almost 5 yearsI wasn't trying to imply that useEffect was the only hook. But for OP's use case there is no point in using a memoized callback. Because his task is to console.log. Yes I have mentioned that point in my text. yes, useEffect fires every time the contents of the array in the 2nd parameter changes.
-
Xen_mar almost 5 yearsthe last comment helped a looooot in understanding this! Tahnks @James!
-
Xen_mar almost 5 yearsCan you guys specify what a memorised callback is? Is it a useMemo hook? Its not a term with lots of google results.
-
Avin Kavish almost 5 years@Jame Changed text, should be clearer for future readers. reactjs.org/docs/hooks-reference.html#usememo
-
James almost 5 years@AvinKavish edit looks much better IMO :) Xen_mar check out useCallback
-
wiktor almost 5 yearsI think useEffect will run only once because observed will never change even if observed.current changes. That is the point of useRef. "The returned object will persist for the full lifetime of the component." codesandbox.io/s/romantic-tharp-dsnpx
-
Mathijs Segers over 4 yearsIn my case it has been set before, but a little bit later it becomes null again.
-
Weston Wedding about 4 yearsUsing refs as useEffect() dependencies is, imo, an antipattern. Any future changes to ref.current will not trigger the useEffect().
-
Avin Kavish about 4 years@WestonWedding this is not a pattern at all, It's a simple and quick way to get the ref printed to the console because the useEffect hook runs after the first render. Yes, since refs exist outside react state, changes to the value will not trigger re-renders. Updated answer.
-
Yash Ojha about 3 yearsworked like a charm. none of the other answers worked for me.
-
Ganesh almost 3 yearsCannot assign to 'current' because it is a read-only property
-
loekTheDreamer about 2 yearsthis doesnt work. i dont understand why there are upvotes.
-
doublejosh almost 2 yearsNo,
rlvRef.current
is not a read only value. The reference is aconst
but.current
is mutable.