useState 在定时器和promise中的执行问题

image.png
为什么 setLoading 和 setSecond 在Promise和setimeout中执行会分别出发两次render,而直接调用的话只会触发一次render
注明: 这里去除useEffect执行前的首次渲染
效果如下
image.png

代码:

function App() {
  const ref = useRef(0)
  const [loading, setLoading] = useState(true);
  const [second, setSecond] = useState([]);
  useEffect(() => {
    console.log('useEffectuseEffectuseEffect')
    setLoading(true)
    
    /**
     * 包含在Promise和setTimeout中 
     * 执行setLoading和setSecond会分别执行两次渲染
     */
    Promise.resolve().then(() => {
      console.log('Promise')
      setLoading(false)
      setSecond([1, 3, 4])
    })
    // setTimeout(() => {
    //   setLoading(false)
    //   setSecond([1, 3, 4])
    // }, 1000)

    // 执行setLoading和setSecond只执行一次渲染
    // setLoading(false)
    // setSecond([1, 3, 4])
  }, []);
  // console.log('mounted ----->', ++ref.current, second)
  return (
    <div>
      { (function() { console.log('render ----->', ref.current, second) })()  }
      { loading && (function(){console.log('loading...')})() }
    </div>
  );
}
阅读 6.3k
2 个回答

react 的batchUpdate 问题,在非react生命周期内以及合成时间内(比如原声事件监听、Promise回调函数、定时器中),react无法预知行为,无法批量合并更新,class组件也一样,可以讲setState或setxxx 放进unstable_batchedUpdates(() => {setXXX();setXXX()})进行批量更新

异步中的变更操作是同步的,不会去收集,所以每次更新都会触发render。 class组件也是一样的表现

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题