React Hook: 为什么 useRef Hook 的. current 为 null?

我有一个简单的组件示例:

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);

我希望 observed.current是类型元素,current 不是空的,而是包含所有属性的 div 元素。我的理解是:

  1. Ref 初始化时值为 null
  2. Null 被 ref 覆盖

但事实证明,.current仍然是空的。这是不好的,因为我想要传递观察到的一个函数,期望一个元素类型的参数。

Https://codesandbox.io/embed/purple-forest-0460k

117308 次浏览

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"
>

Code Sandbox

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);

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); }}
...
/>
)

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>);