Javascript 在DOM更新后运行的React钩子

Javascript 在DOM更新后运行的React钩子,javascript,reactjs,dom,react-hooks,Javascript,Reactjs,Dom,React Hooks,我有一个React应用程序,其中我基于状态隐藏/显示一个元素,并希望在状态变量更改后对该DOM元素进行一些计算 我尝试过使用useLayoutEffect,但它仍然在DOM更新之前运行,因此我的计算没有用。我对useLayoutEffect的理解是否错误?我用错了吗 这是我的 constmycomponent=()=>{ 常量elem=useRef() 常量[isElemVisible,setIElemVisible]=useState(false) useLayoutEffect(()=>{

我有一个React应用程序,其中我基于状态隐藏/显示一个元素,并希望在状态变量更改后对该DOM元素进行一些计算

我尝试过使用
useLayoutEffect
,但它仍然在DOM更新之前运行,因此我的计算没有用。我对
useLayoutEffect
的理解是否错误?我用错了吗

这是我的

constmycomponent=()=>{
常量elem=useRef()
常量[isElemVisible,setIElemVisible]=useState(false)
useLayoutEffect(()=>{
//我希望在从DOM中添加/删除元素后运行此操作
//而是在DOM中实际修改元素之前运行(但ref本身已更改)
elem.current.getBoundingClientRect()//如果此对象存在,请对此对象执行操作
},[elem.current])
返回(
{iselem&&(
)}
)
}

一个简单的解决方案是在
useffect
hook中手动检查状态更新:

constmycomponent=()=>{
常量elem=useRef()
常量[isElemVisible,setIElemVisible]=useState(false)
useffect(()=>{
如果(可见){
//假设UI已更新:
elem.current.getBoundingClientRect()//对该对象执行某些操作
}
},[isElemVisible])
返回(
{iselem&&(
)}
)
}

您可以尝试将函数作为ref传递,并在该函数中执行以下操作:

const myComponent = () => {

  // other component code

  const elemRef = useCallback((node) => {
    if (node !== null) {
      // do stuff here
    }
  }, [])


  return (
   <div id="base-element">
    { isElemVisible && (
      <div id="element" ref={elemRef}></div>
    )}
   </div>
  )
}
constmycomponent=()=>{
//其他组件代码
const elemRef=useCallback((节点)=>{
如果(节点!==null){
//在这里做事
}
}, [])
返回(
{iselem&&(
)}
)
}

看看这个

你几乎做对了

useRef.current在组件生命周期中将始终指向同一对象,并且仅会显式更改(如elem.current=某些渲染上的某个对象)

但您可以检查isElemVisible何时会更改,并在更改后触发回调:

const myComponent = () => {

  const elem = useRef()
  const [isElemVisible, setIElemVisible] = useState(false)

  useLayoutEffect(() => {
    if(isElemVisible)
      elem.current.getBoundingClientRect()
  }, [isElemVisible])


  return (
   <div id="base-element">
    { isElemVisible && (
      <div id="element" ref={elem}></div>
    )}
   </div>
  )
}
constmycomponent=()=>{
常量elem=useRef()
常量[isElemVisible,setIElemVisible]=useState(false)
useLayoutEffect(()=>{
如果(可见)
elem.current.getBoundingClientRect()
},[isElemVisible])
返回(
{iselem&&(
)}
)
}

您有错误的依赖项-
isElementVisible
未在效果中使用,但
elem.current
是。如果你打开了门楣,门楣就会告诉你这个。钩子将在开始时运行一次,但只有在依赖项发生变化时才会运行。因此,依赖于ref而不是trigger state值将使效果由其原因触发。此外,
const bbox=elem.current&&elem.current.getBoundingClientRect()
,因为删除元素时,current的值将是未定义的。谢谢。从技术上讲,这两方面都是正确的。我省略了存在性检查,因为它在本例中没有真正的帮助。当我向deps添加
elem.current
时,效果仍然在DOM更改之前运行。这似乎是像
componentWillUpdate
一样运行,而不是在DOM更新之后但在浏览器绘制之前运行
componentdiddupdate
,这样您就可以基于(例如)边界框更改某些内容,在用户看到任何更改之前再次运行该函数。既然你没有在效果中做任何特别有用的事情,你怎么知道它什么时候运行呢?我想你可能在这里了解了一些东西根据你的例子,到底应该用什么来更新组件状态?我有一个按钮,可以调用
setiselevisible