简体   繁体   English

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

[英]Using React.forwardRef inside render function directly

Is it safe to use React.forwardRef method directly inside render function of another component - 在另一个组件的渲染函数中直接使用React.forwardRef方法是否安全-

Example - 范例-

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>
  );
}

As you see it's a temporary workaround for a bug in Next.js v9 - https://github.com/zeit/next.js/issues/7915 . 如您所见,这是Next.js v9中的错误的临时解决方法-https: //github.com/zeit/next.js/issues/7915

Beware forwardRef affects reconciliation: element is always re-created on parent re-rendering. 当心forwardRef会影响和解:始终在父级重新渲染时重新创建元素。

Say

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>
  );
}

You may see that after clicking button forwardRef -ed input is dropped and re-created so it's value becomes empty. 您可能会看到单击按钮forwardRef后,输入的输入被丢弃并重新创建,因此其值变为空。

Not sure if this could be important for <Link> but in general it means things you'd expect to run only once per life time(say fetching data in componentDidMount or useEffect(...,[]) as alternative) will happen much more frequently. 不确定这对<Link>是否重要,但总的来说,这意味着您希望每个生命周期仅运行一次(例如,在componentDidMountuseEffect(...,[])获取数据)会发生很多更频繁。

So if choosing between this side effect and mocking warning I'd rather ignore Warning. 因此,如果在这种副作用和嘲笑警告之间进行选择,我宁愿忽略警告。 Or create own <Link > that will not cause warnings. 或创建自己的<Link >不会引起警告。

[UPD] missed one thing: React checks forwardRef by reference in this case. [UPD]遗漏了一件事:在这种情况下,React通过引用检查forwardRef So if you make forwardRef out of the render (so it's referentially the same) it will not be recreated: 因此,如果您从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>
  );
}

But still I believe it's safer to ignore warning than to introduce such a workaround. 但是我仍然相信,忽略警告比引入这种解决方法更安全。

Code above has worse readability to me and is confusing("why ref is not processed at all? was it intentional? why this forwardRef is here and not in component's file?") 上面的代码对我而言可读性较差,并且令人困惑(“为什么不完全处理ref ?是故意的?为什么此forwardRef此处而不在组件的文件中?”)

I concurr with skyboyer, I'll add that it might be possible to create the forwardRef component outside of the render function to avoid re-creating the component each render. 我同意skyboyer,我要补充一点,可能可以在render函数之外创建forwardRef组件,以避免重新创建每个渲染组件。 To be checked. 被检查。

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>
  )
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM