3

我在功能组件中使用 reactuseRef来获取 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 ,
});

但是当我的父组件 ummounts 我得到错误:

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

在此处输入图像描述

我无法想象有什么问题;

4

2 回答 2

2

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

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

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

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

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

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

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

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

然而,就像前向裁判文档提到的那样:

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

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

于 2021-02-05T18:17:44.663 回答
2

你不能只传递 aref作为道具。

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

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

更多在文档中。

于 2021-02-05T17:24:10.030 回答