简体   繁体   English

React:关于使用 ref 和 useLayoutEffect 来确定组件是挂载还是卸载的问题

[英]React: question about using ref and useLayoutEffect to determine if a component is mounted or unmounted

I have a component like this我有一个这样的组件

function App() {
  const mounted = useRef()
  useLayoutEffect(() => {
    mounted.current = true
    return () => {
      console.log('unmounted') // this does not get called when I unmount the component
      mounted.current = false
    }
  }, [])

  if (mounted.current) {
    console.log('mounted')
  }
  return (
    <div>
      {/* this hello world div doesn't get rendered on the screen👇, I thought useLayoutEffect would be called before browser paints screen */}
      {mounted.current && <div>hello world</div>}
    </div>
  )
}

I know that useEffect serves the purpose too.我知道useEffect可以达到目的。 I used useLayoutEffect is because it runs a bit earlier than useEffect .我使用useLayoutEffect是因为它比useEffect运行得早一点。 According to this https://github.com/donavon/hook-flow hook flow diagram.根据这个https://github.com/donavon/hook-flow钩子流程图。

My question is:我的问题是:

  1. After I unmount the component, I don't see console.log('unmounted') gets run卸载组件后,我没有看到console.log('unmounted')运行
  2. I was expecting <div>hello world</div> to get rendered on the screen after I refresh the page since I the useLayoutEffect callback would run before browser paints the screen by that time when it paints the screen, the ref is set to true by the callback.我期待<div>hello world</div>在我刷新页面后呈现在屏幕上,因为我useLayoutEffect回调会在浏览器绘制屏幕之前运行,当它绘制屏幕时,ref 设置为 true通过回调。

I was expecting hello world to get rendered on the screen after I refresh the page since I the useLayoutEffect callback would run before browser paints the screen by that time when it paints the screen, the ref is set to true by the callback.我期待 hello world 在我刷新页面后呈现在屏幕上,因为我 useLayoutEffect 回调会在浏览器绘制屏幕之前运行,当它绘制屏幕时,ref 被回调设置为 true。

Although useLayoutEffect runs more quickly than useEffect , it's still asynchronous .虽然useLayoutEffect比运行更快useEffect它仍然是异步的 It's similar to the difference between setTimeout(fn, 0) and setTimeout(fn, 60) .它类似于setTimeout(fn, 0)setTimeout(fn, 60)之间的区别。 The useLayoutEffect callback will not run until after the functional component has returned, but it will run before the user can see the new element. useLayoutEffect回调直到功能组件返回后才会运行,但在用户看到新元素之前运行。

So, since mounted.current is false the first time the component renders, and since no state changes occur, it doesn't re-render, and hello world doesn't appear.因此,由于mounted.current在组件第一次渲染时为false,并且由于没有发生状态更改,因此不会重新渲染,并且不会出现hello world

After I unmount the component, I don't see console.log('unmounted') gets run卸载组件后,我没有看到 console.log('unmounted') 运行

Works fine here, I see it:在这里工作正常,我看到了:

 function App() { const mounted = React.useRef() React.useLayoutEffect(() => { mounted.current = true return () => { console.log('unmounted') // this does not get called when I unmount the component mounted.current = false } }, []) if (mounted.current) { console.log('mounted') } return ( <div> {/* this hello world div doesn't get rendered on the screen👇, I thought useLayoutEffect would be called before browser paints screen */} {mounted.current && <div>hello world</div>} </div> ) } const Outer = () => { const [show, setShow] = React.useState(true); React.useEffect(() => { setTimeout(() => { setShow(false); }, 2000); }, []); return ( show ? <App /> : null ); }; ReactDOM.render(<Outer />, document.querySelector('.react'));
 <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div class='react'></div>

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

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