Javascript 为什么react`useRef`hook将对象存储在`current`属性中?为什么它不能直接存储在ref对象中?

Javascript 为什么react`useRef`hook将对象存储在`current`属性中?为什么它不能直接存储在ref对象中?,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,为什么useRefhook返回的对象会存储它在current属性中应该保存的任何值?为什么我们不能直接向ref对象赋值,如下所示: 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返回另一个包含

为什么
useRef
hook返回的对象会存储它在
current
属性中应该保存的任何值?为什么我们不能直接向ref对象赋值,如下所示:

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
返回另一个包含
current
属性的对象中的参数的目的是什么?

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

参考:


函数mountRef(初始值:T):{current:T}{
const hook=mountWorkInProgressHook();
const ref={current:initialValue};
如果(开发){
对象。印章(参考);
}
hook.memorizedState=ref;
返回ref;
}

react hooks系统使用不可变的值。每当呈现组件时,都会调用钩子(例如
useState
hook),并生成一个或两个值(state和setter函数)。如果此值与以前的值不同,则可能会调用其他挂钩(
useffect
初始化setter函数时)

然而,有时我们不想对这种变化做出反应。我们并不在乎价值是什么,只要它存在,我们也不在乎是否有什么东西改变了它。对于这种情况,我们有:

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


无论何时需要存储值,都将使用该值,但不会导致重新渲染,也不会导致
usemo
useCallback
useffect
等。。。要重新计算,您可以通过ref设置该值。因为ref本身将用作钩子依赖项的一部分(
usemo(()=>{},[ref]
),您无法更新它。若要启用不变性,可以更改
ref
对象中的属性
ref.current
,而不会导致依赖项重新计算,因为它是同一个ref.

此问题的答案不特定于React及其hooks系统。 改变对象只是解决如何在不同的闭包/作用域之间共享值的一种方法

当您为您的组件调用
useRef()
时,将在React内部创建一个“ref对象”,该对象绑定到组件的特定实例。 每次跨多个渲染调用
useRef()

通过这样做

let value = useRef();
value = 1234;
您正在丢弃ref对象,并在本地作用域中将其替换为新值。React无法跟踪该操作并更新存储在其内部的ref对象。(事实上,React不会跟踪“ref对象”的任何操作,它只会将它们提供给您。您可以对它们进行变异,然后访问它们)

但使用当前的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对象,以便您可以使用之前设置的值。

我试图回答您问题的根本原因,我将其解释为:“似乎我们不需要具有.current属性的中间对象。”你是对的。我们没有。无论关于
useRef
的实际原因是什么,我已经注意到可以改为执行以下操作,这与你在问题中要求的语法相同(删除
.current
):

这使我们可以直接变异
foo
的属性,而不必使用
.current
。只要我们从不调用
setFoo
,变异
foo
的属性本身就不会导致重新渲染器。
foo
本身的值永远不会改变,因为它总是指向同一个对象或数组

但是,与任何其他变量(包括
useRef
变量)一样,如果
useffect
的第二个参数数组中出现更改的属性(如
foo.bar
),则可能会导致
useffect
钩子在重新加载后重新运行


我还没有尝试过让[foo]=useState(“随便什么”)
还没有。在这种情况下,我们将更改
foo
的实际值,并根据React在后续的重新加载时将更改后的值返回给我们,即使我们从未通知React更改。看起来很粗略。

因为ref本身将用作挂钩依赖项的一部分(useMemo(()=>{},[ref]),。你的意思是作为useRef依赖性的一部分吗?不。ref将被其他挂钩使用,例如usemo或useffect依赖性,其思想是在第一次更改(ref的init)后,对ref进行变异(更改当前)不会导致依赖项重新计算-即UseMoom调用函数以再次生成值。那么useRef和useState或useReducer之间有什么不同呢?因此您说要启用不可变性?不同之处在于更改一个ref(当前)并不能替换整个ref。“react hooks系统使用不可变值工作”。等等,什么?
useRef()
是一个钩子。它确实返回一个可变对象。
ref.current=“newValue”
正在对该对象进行变异。“正如您所知,如果要记忆某个对象,我们需要将其转换为对象或数组。”-你能解释一下为什么我应该知道吗?不可能记住数字或字符串?是的,应该可以记住每个js类型,但正如我所知,两个对象或数组不相等。表示{}=={}为false或[]==[]但是1===1是真的,这是因为1是1,但没有对象与另一个对象是同一个对象
//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);