直接在 render 函数中使用 React.forwardRef

Using React.forwardRef inside render function directly

直接在另一个组件的渲染函数中使用React.forwardRef方法是否安全-

例子-

function Link() {
  // --- SOME EXTENSIVE LOGIC AND PROPS CREATING GOES HERE ---
  // --- OMITTED FOR SIMPLICITY ---

  // TO DO: Remove forward ref as soon Next.js bug will be fixed -
  // https://github.com/zeit/next.js/issues/7915

  // Please note that Next.js Link component uses ref only to prefetch link
  // based on its availability in view via IntersectionObserver API -
  // https://github.com/zeit/next.js/blob/canary/packages/next/client/link.tsx#L119
  const TempShallow = React.forwardRef(props =>
    cloneElement(child, {
      ...props,
      ...baseProps,
      onClick: handleClick
    })
  );

  return (
    <NextLink href={href} as={as} prefetch={prefetch} passHref {...otherProps}>
      <TempShallow />
    </NextLink>
  );
}

如您所见,这是针对 Next.js v9 - https://github.com/zeit/next.js/issues/7915.

中的错误的临时解决方法

注意 forwardRef 影响协调:元素总是在父重新渲染时重新创建。

function App() {
  const [,setState] = useState(null);
  const Input = React.forwardRef((props, ref) => <input {...props} />)
  return (
    <div className="App">
      <h1>Input something into inputs and then click button causing re-rendering</h1>
      <Input placeholder="forwardRef" />
      <input placeholder="native" />
      <button onClick={setState}>change state to re-render</button>
    </div>
  );
}

您可能会看到,在单击按钮 forwardRef 后,输入被删除并重新创建,因此它的值变为空。

不确定这对 <Link> 是否重要,但总的来说,这意味着您希望一生只 运行 一次(比如在 componentDidMountuseEffect(...,[]) 作为备选)将更频繁地发生。

因此,如果要在这种副作用和模拟警告之间做出选择,我宁愿忽略警告。或者创建自己的 <Link > 不会引起警告。

[UPD] 遗漏了一件事:在这种情况下,React 通过引用检查 forwardRef。因此,如果您从 render 中创建 forwardRef(因此它在引用上是相同的),它将不会被重新创建:

const Input = React.forwardRef((props, ref) => <input {...props} />)

function App() {
  const [,setState] = useState(null);
  return (
    <div className="App">
      <h1>Input something into inputs and then click button causing re-rendering</h1>
      <Input placeholder="forwardRef" />
      <input placeholder="native" />
      <button onClick={setState}>change state to re-render</button>
    </div>
  );
}

但我仍然相信忽略警告比引入这样的解决方法更安全。

上面的代码对我来说可读性较差并且令人困惑("why ref is not processed at all? was it intentional? why this forwardRef is here and not in component's file?")

我同意 skyboyer 的观点,我要补充一点,可以在渲染函数之外创建 forwardRef 组件,以避免每次渲染都重新创建组件。待审核。

const TempShallow = React.forwardRef(({ child, ...props }) => React.cloneElement(child, props))

function Link() {
  // --- SOME EXTENSIVE LOGIC AND PROPS CREATING GOES HERE ---
  // --- OMITTED FOR SIMPLICITY ---

  // TO DO: Remove forward ref as soon Next.js bug will be fixed -
  // https://github.com/zeit/next.js/issues/7915

  // Please note that Next.js Link component uses ref only to prefetch link
  // based on its availability in view via IntersectionObserver API -
  // https://github.com/zeit/next.js/blob/canary/packages/next/client/link.tsx#L119


  return (
    <NextLink href={href} as={as} prefetch={prefetch} passHref {...otherProps}>
      <TempShallow {...props} {...baseprops} child={child} onClick={onClick} />
    </NextLink>
  )
}