为什么反应useRef钩子将对象存储在current属性中?为什么不能将其直接存储在ref对象中?

时间:2019-12-15 05:33:24

标签: javascript reactjs react-hooks

为什么let transporter = nodemailer.createTransport({ service: 'gmail', port: 465, secure: true, auth: { user: 'myemail@gmail.com', pass: 'mypass' } }); 钩子返回的对象存储应该保存在useRef属性中的任何值?我们为什么不能直接将一些东西分配给ref对象,如下所示:

current

const sampleRef = useRef([]); /** why can't we do this... */ sampleRef.push('1'); /** ...instead of this? Why an extra `current` object? */ sampleRef.current.pus('1'); 返回包装在具有useRef属性的另一个对象中的参数的目的是什么?

4 个答案:

答案 0 :(得分:1)

据我了解,他们之所以这么做,是因为他们需要创建一个对象来密封 DOM元素对象(在开发模式下)并记忆。如您所知,如果我们要记住一些东西,我们需要将其转换为对象数组

参考:

RA_Min_1

https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.js#L916

答案 1 :(得分:1)

react hooks系统使用不可变的值。无论何时呈现组件,都会调用该挂钩(例如useState挂钩),并且它们会生成一个或两个值(状态和设置函数)。如果此值与以前的值有所不同,则可能会调用其他钩子(初始化setter函数时{useEffect)。

但是,有时我们不想对这些更改做出反应。只要价值存在,我们就不会在乎什么,我们也不会在乎是否有所改变。对于这种情况,我们有ref

  

“ ref”对象是一个通用容器,其当前属性为   可变并且可以保存任何值,类似于   课。

无论何时需要存储值,都将使用该值,但不会导致重新渲染,也不会导致useMemouseCallbackuseEffect等。要重新计算,您可以通过引用设置该值。由于ref本身将用作挂钩依赖项(useMemo(() => {}, [ref])的一部分,因此您无法对其进行更新。为了实现不变性,ref对象内部的属性可以更改ref.current,而无需重新计算依赖项,因为它是相同的引用。

答案 2 :(得分:1)

这个问题的答案并不特定于React及其钩子系统。 更改对象只是解决如何在不同的闭包/范围之间共享值的解决方案。

当您为组件调用useRef()时,在React内部会创建一个“ ref对象”,并绑定到该组件的特定实例。 每次跨多个渲染调用useRef()时,都会返回相同的“ ref object”。在其上设置current是您存储值以在下一次渲染时重新访问它的方式。

通过类似的操作

let value = useRef();
value = 1234;

您将丢弃ref对象,并在本地范围内将其替换为新值。 React不可能跟踪该动作并更新存储在其内部的ref对象。 (实际上,React始终不会跟踪“引用对象”的任何动作,它只是将它们提供给您。您对它们进行突变,然后进行访问)。

但是使用当前的API,您可以

const ref = useRef(); // ref is an object that is stored somewhere in React internals
ref.current = 1234; // you update the property of that object

下次渲染组件时,React为您提供相同的ref对象,以便您可以使用之前设置的值。

答案 3 :(得分:0)

我正在尝试回答您问题的根本原因,我将其解释为:“似乎我们不需要具有.current属性的中间对象。”没错我们没有。无论关于useRef的实际原因是什么,我都注意到有可能改为执行以下操作,该操作具有您在问题中所要求的语法(消除了.current): / p>

//note foo is in array brackets by itself
const [foo /*no setFoo here*/]= useState({bar:"baz"});
...
foo.bar="hello"

//note foo in brackets by itself
const [foo /*no setFoo here*/]= useState([]);
...
foo.push(1);

这使我们可以直接更改foo的属性,而无需使用.current。只要我们从不调用setFoo,对foo的属性进行更改就不会导致自身的重新渲染。 foo本身的值永远不会更改,因为它始终指向同一对象或数组。

但是,如果像useRef这样的已更改属性出现在重新渲染之后,则与其他变量(包括useEffect一样,有可能导致foo.bar钩子在重新渲染后重新运行)。 useEffect的第二个参数数组。

我还没有尝试let [foo]= useState("whatever")。在这种情况下,我们将更改foo的实际值,并依靠React在以后的重新渲染时将更改后的值返回给我们,即使我们从未通知过该更改。似乎很粗略。