渲染是否发生在 React Hooks useEffect 中的函数被调用之前?

Does a render happen before function in React Hooks useEffect is called?

我原以为 useEffect 的第一个函数在第一次渲染之前被调用,但是当我调用下面的方法时,我的 console.log 就在 return 方法调用被调用之前,然后 useEffect 的第一个参数函数被调用。

调用顺序:

just before render return
ImageToggleOnScroll.js:8 useEffect before setInView
ImageToggleOnScroll.js:10 useEffect after setInView

来源:

import React, {useState,useRef,useEffect} from "react";

// primaryImg is black and white, secondaryImg is color
const ImageToggleOnMouseOver = ({ primaryImg, secondaryImg }) => {
    const imageRef = useRef(null);

    useEffect(() => {
        console.log('useEffect before setInView')
        setInView(isInView());
        console.log('useEffect after setInView')
        window.addEventListener("scroll", scrollHandler);

        return () => {
            window.removeEventListener("scroll", scrollHandler);
        };
    }, []);

    const isInView = () => {
        if (imageRef.current) {
            const rect = imageRef.current.getBoundingClientRect();
            return rect.top >= 0 && rect.bottom <= window.innerHeight;
        }
        return false;
    };

    const [inView, setInView] = useState(false);
    const scrollHandler = () => {
        setInView(() => {
            return isInView();
        });
    };

    console.log('just before render return')
    return (
        <img
            ref={imageRef}
            src={inView ? secondaryImg : primaryImg}
            alt="image here"
        />
    );
};

export default ImageToggleOnMouseOver;

根据 useEffect documentation:

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

所以是的,它在第一次渲染和每个后续渲染之后运行。

使用 useEffect 创建的效果 运行 在渲染提交阶段之后,因此在渲染周期之后。这是为了确保在渲染提交阶段不会执行可能导致不一致的副作用

根据文档

Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React’s render phase). Doing so will lead to confusing bugs and inconsistencies in the UI.

The function passed to useEffect will run after the render is committed to the screen.

useEffect 挂钩可用于复制 class 组件的 componentDidMountcomponentDidUpdatecomponentWillUnmount 生命周期方法的行为,具体取决于传递给的参数作为 useEffect 的第二个参数的依赖项数组和回调中的 return 函数在下一个效果之前执行 运行 或在卸载

之前

对于某些用例,例如 animations,您可以使用 useLayoutEffect,它在所有 DOM 突变之后同步执行。使用它从 DOM 读取布局并同步重新渲染。在浏览器有机会绘制之前,useLayoutEffect 内安排的更新将被同步刷新。