无法在 React useRef 中分配只读属性“current”

问题描述

我在功能组件中使用 react useRef获取 html 对象上的链接并将其存储在 Recoil atom 中。例如:

const Children = () => {
  const [refLink,setSrefLink] = useRecoilState(refLink)
  return <input ref={someRef}/>
}
const Parent = () => {
  const [refLink,setSrefLink] = useRecoilState(refLink)
  const someRef = useRef();
  setSomeRef(someRef)
  return <Children />;
}

export const refLink = atom({
    key: 'refLink',default: null,});

但是当我的父组件卸载时出现错误

react-dom.development.js:20997 未捕获的类型错误:无法分配给 文件中对象“#”的只读属性“当前” reac-dom.development.js

enter image description here

我无法想象这是什么问题;

解决方法

您不能只将 ref 作为道具传递。

通常,组件隐藏其实现,因此父组件不应该能够访问子组件创建的 DOM 元素。但在极少数情况下,您希望在组件上允许这样做,您必须使用 forwardRef 显式这样做:

    const Children = React.forwardRef((props,someRef) => {
// −−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      return <input ref={someRef}/>
    });
// −−^
    const Parent = () => {
      const someRef = useRef();
      return <Children ref={someRef} />;
    };

the documentation 中的更多内容。

,

这里的问题是原子在默认情况下是冻结的(请参阅 documentation),并且 ref 通过改变对象的 current 属性来工作。

您可以通过传递 dangerouslyAllowMutability: true 来防止对象冻结。

export const refLinkState = atom({
    key: 'refLink',default: null,dangerouslyAllowMutability: true,});

请注意,如果引用本身被另一个引用替换,这只会更新所有订阅者。如果 ref 使用者更改 current 属性,订阅者将不会重新呈现,因为 ref 对象仍然是同一个对象。

您可以通过不使用 ref 来解决此问题,而是将 ref 值直接传递到您的共享状态。

// without dangerouslyAllowMutability
export const refLinkState = atom({
    key: 'refLink',});

const Children = () => {
  const [refLink,setRefLink] = useRecoilState(refLinkState);
  return <input ref={setRefLink} />;
};

在上面的场景中,我们已经完全消除了 refs,而是将 DOM 元素存储在没有 ref 包装器的反冲状态。

但是就像 forward refs documentation 提到的那样:

React 组件隐藏了它们的实现细节,包括它们的渲染输出。其他使用 FancyButton 的组件通常不需要 obtain a ref 到内部的 button DOM 元素。这很好,因为它可以防止组件过度依赖彼此的 DOM 结构。

在不太了解结构以及您想要实现的目标的情况下,您可以例如提取 Child 中的相关数据并将其存储在共享状态中。但是如果我们有更多的上下文,可能会有更好的解决方案。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...