Reputation: 9742
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:
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.
https://codesandbox.io/embed/purple-forest-0460k
Upvotes: 110
Views: 177059
Reputation: 159
I needed to set a value into the useRef()-variable which was retrieved by an async http-request and was saved in a useState()-variable. So i needed to provide it as an dependency as well in the useEffect()-function:
const [object, setObject] = useState('');
const fetchObject = useCallback(async () => {
const res = await fetch(apiUrl + "/object/", {});
setObject({ ...await res.json() });
}, [apiUrl]);
const jsonEditor = React.createRef();
useEffect(() => {
fetchObject();
if (jsonEditor.current && object.json) {
jsonEditor.current.jsonEditor.set(JSON.parse(object.json));
}
}, [fetchObject, object.json]);
return (
<div>
<JsonEditor
ref={jsonEditor}
onChangeText={onChangeTextHandler}
/>
</div>);
Upvotes: 1
Reputation: 5927
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); }}
...
/>
)
Upvotes: 26
Reputation: 8947
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"
>
Upvotes: 110
Reputation:
At the time the console.log
happens, the ref
isn't yet set. Try putting your console.log
into a useEffect
hook and it works as you want it to.
import React, { useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const observed = useRef(null);
useEffect(() => {
console.log(observed.current);
}, [observed]);
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);
Upvotes: 19