1

我有一个sidebarCart组件,基本上是一个购物车组件,它被包裹在forwardRef钩子中,并包含useImperativeHandle以将函数传递给父级 App。在我引入useContext钩子之前一切正常,现在sidebarCart中的 refs 变为空,这是什么奇怪的行为?

我正在谈论的参考是cartContainerpageShdowCover 我发现当我停止我的 nodejs 服务器时,这个问题就消失了。

这是sidebarCart组件。

import React ,{createRef,forwardRef,useImperativeHandle,useContext,useEffect}from 'react'
import CartItem from './CartItem'
import {MyContext} from '../../Context/ProductsProvider'


const SideBarCart=forwardRef((props,ref)=>{
    const {setCart,cart} =useContext(MyContext)
    const cartContainer  = createRef()
    const pageShdowCover = createRef()

    const slideOut=e=>{
        cartContainer.current.style.right='-400px'
        pageShdowCover.current.style.opacity='0'
        setTimeout(()=>pageShdowCover.current.style.display='none', 600);
    }
    useImperativeHandle(ref, () => ({
        slideIn(){
           pageShdowCover.current.style.display='block'
           cartContainer.current.style.right='0'
           pageShdowCover.current.style.opacity='1'
        }
    }),[pageShdowCover,cartContainer]);
 
    return (
        <div>
            <div className="pageShdowCover"  ref={pageShdowCover}  ></div>
            <div className="SideContainer cart" ref={cartContainer}>
                <div className="cart__top">
                    <h1>Cart</h1>
                   <i className="far fa-times-circle Close" onClick={slideOut}></i>  
                   <a onClick={slideOut}>x</a>
                </div>
                <div className="cart__body">  
                </div>
        </div>
        </div>
    )
})

export default SideBarCart
4

1 回答 1

2

我认为useContext钩子会导致子级重新渲染而没有父级重新渲染。Refs 在更改时不会触发重新渲染,因此从父级传递给子级的 refs 可能是陈旧的?(我认为这就是答案——我可能不正确)。

总之(对我有用):要解决我遇到的问题,只需将 ref 存储在 state 中,以便在 ref 更改时触发重新渲染

===

解释

我的用例是我有一个有 4 个孩子的父组件。其中一个孩子是一个标题,我希望兄弟姐妹能够在使用渲染时“注入”控件ReactDOM.createPortal

- Parent
 - Header
 - A
 - B
 - C  

我发现如果我只使用一个 ref,那么当 ref 分配给 DOM 时,父级不会重新渲染,因此 components A, B,C不会重新渲染,因此他们不知道新分配的ref.current值。

IE以下不起作用

const Parent = () => {
  const ref = useRef()

  return (
   <div>
    <Header ref={el => { ref.current = el } />
    <C ref={ref} />
    <B ref={ref} />
    <C ref={ref} />
   </div>
  )
}

// A, B, C have the same signature
const A = forwardRef((props, ref) => {
  return (
    <div>
      {createPortal(<SomeComponent />, ref.current)}
      <OtherComponent />
    </div>
  )
})

我在 StackOverflow 上的这个答案中找到了解决方案。我来这个问题是因为A,BC正在使用useContext(...). 以前对我来说,当创建状态Parent而不是使用上下文时,上面的代码可以工作 - 可能是因为父级正在重新渲染并留下陈旧的参考或其他东西(我认为它“意外地”工作)。即问题与上下文无关,而是如何触发重新渲染。

此代码确实有效

const Parent = () => {
  const [ref, setRef] = useState()

  return (
   <div>
    <Header ref={el => { setRef(el) } />
    <C ref={ref} />
    <B ref={ref} />
    <C ref={ref} />
   </div>
  )
}

// A, B, C have the same signature
const A = forwardRef((props, ref) => {
  return (
    <div>
      {createPortal(<SomeComponent />, ref)}
      <OtherComponent />
    </div>
  )
})
于 2021-03-10T09:17:30.950 回答