React Hooks:为啥 useRef Hook 的 .current 为空?

Posted

技术标签:

【中文标题】React Hooks:为啥 useRef Hook 的 .current 为空?【英文标题】:React Hooks: Why is .current null for useRef Hook?React Hooks:为什么 useRef Hook 的 .current 为空? 【发布时间】:2019-10-25 17:40:52 【问题描述】:

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

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 的类型为 element 并且 current 不会为空,而是 div 元素及其所有属性。我的理解是:

    ref 被初始化为 null 值 Null 被 ref 覆盖

但事实证明,.current 仍然是空的。这很糟糕,因为我想将观察到的参数传递给需要元素类型参数的函数。

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

【问题讨论】:

【参考方案1】:

Ref.current 为 null,因为直到函数返回并呈现内容后才会设置 ref。每次传递给它的数组内容的值发生变化时,useEffect 钩子都会触发。通过在数组中传递 observed 并将记录 observed 的回调传递到控制台,可以利用 useEffect 挂钩来完成您的任务。

  useEffect(() => 
    console.log(observed.current);
  , [observed]);

编辑:这仅适用于第一次渲染,因为对 ref 的更改不会触发重新渲染。但是关于 useEffect 的一般说法仍然成立。如果要观察 dom 元素的 ref 的变化,可以使用 callback as ref.

  <div 
    ref=el =>  console.log(el); observed.current = el;  // or setState(el)
    className="App"
  >

Code Sandbox

【讨论】:

非常感谢!我对 Hooks 非常了解,但对于功能组件,我会假设整个功能是“渲染功能”。您是否可以参考我在渲染函数中可以做和不能做的事情? “你必须检查 useEffect 钩子中的值” - 这句话严格来说不正确,我可以记住可以访问 ref 的回调函数。要点是 ref 为 null 因为 UI 尚未真正呈现,useEffect 在这里工作,因为 useEffect 它等同于 componentDidMount 和其他一些运行 after 的钩子组件已渲染。 @Jame 更改了文本,对未来的读者来说应该更清楚。 reactjs.org/docs/hooks-reference.html#usememo @AvinKavish 编辑看起来好多了 IMO :) Xen_mar 查看useCallback 我认为 useEffect 只会运行一次,因为即使观察到的电流发生变化,观察到的也永远不会改变。这就是 useRef 的意义所在。 “返回的对象将在组件的整个生命周期内持续存在。” codesandbox.io/s/romantic-tharp-dsnpx【参考方案2】:

console.log 发生时,ref 尚未设置。尝试将您的 console.log 放入 useEffect 钩子中,它会按您的意愿工作。

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

【讨论】:

【参考方案3】:

这是我最终做的,因为在 rlvRef 上调用 useEffect 并没有捕获所有事件。

const rlvRef = useRef()
const [refVisible, setRefVisible] = useState(false)

useEffect(() => 
  if (!refVisible)  
    return
  
  // detected rendering
, refVisible)

return (
  <RecyclerListView
    ref=el =>  rlvRef.current = el; setRefVisible(!!el); 
    ... 
  />
)

【讨论】:

就像一个魅力。其他答案都不适合我。 不能分配给'current',因为它是一个只读属性

以上是关于React Hooks:为啥 useRef Hook 的 .current 为空?的主要内容,如果未能解决你的问题,请参考以下文章

react hooks 之 useRef, useImperativeHandle

在 React-Hooks UseRef 我无法获得新的状态值

ZF_react hooks useEffect的实现 useRef useImperativeHandle的实现,react整体功能实现完毕

react hooks

react hooks

react hooks