我正在尝试学习 react Hook 。我需要帮助来理解 react 函数是否始终在每次渲染时重置钩子(Hook)状态。
这是我试图修复标题的滚动的一个小例子

class Header extends Component {


    constructor(props) {
        super(props);
        console.log("Constructor")
        this.state = {fixed: false};
    }


    handleScroll = () => {
        console.log(window.scrollY);
        console.log(this.state.fixed);
        if (window.scrollY >= 25 && !this.state.fixed) {
            this.setState({
                fixed: true
            });
        } else if(window.scrollY < 25 && this.state.fixed){
            this.setState({
                fixed: false
            });
        }
    }

    componentDidUpdate(prevProps, prevState, snapshot) {
        console.log("updated ");
    }

    componentDidMount() {
        console.log("added");
        window.addEventListener('scroll', this.handleScroll);
    }

    componentWillUnmount() {
        console.log("removed");
        window.removeEventListener('scroll', this.handleScroll);
    }

    render() {
        return (
            <div></div>
        );
   }
}
输出:
Header.js:26 Constructor
Header.js:51 added
Header.js:32 1
Header.js:33 false
Header.js:32 2
Header.js:33 false
Header.js:32 5
Header.js:33 false
Header.js:32 9
Header.js:33 false
Header.js:32 15
Header.js:33 false
Header.js:32 20
Header.js:33 false
Header.js:32 26
Header.js:33 false
Header.js:47 updated
Header.js:32 31
Header.js:33 true
Header.js:32 35
Header.js:33 true
Header.js:32 38
Header.js:33 true
Header.js:32 40
Header.js:33 true
Header.js:32 39
Header.js:33 true
Header.js:32 38
Header.js:33 true
Header.js:32 35
Header.js:33 true
Header.js:32 31
Header.js:33 true
Header.js:32 25
Header.js:33 true
Header.js:32 20
Header.js:33 true
Header.js:47 updated
Header.js:32 9
Header.js:33 false
Header.js:32 5
Header.js:33 false
Header.js:32 2
Header.js:33 false
Header.js:32 0
Header.js:33 false
它工作正常。
现在,使用react Hook 具有相同的逻辑。我只是想寻找FixedHeader状态的行为。
const Header = props => {

    console.log("rendering");
    const [FixedHeader, setFixedHeader] = useState(false);

    useEffect(() => {
        document.addEventListener("scroll", () => {
            console.log(window.scrollY);
            console.log(FixedHeader);
            if (window.scrollY >= 30) {
                setFixedHeader(true);
            } else {
                setFixedHeader(false);
            }
        })
    }, []);


    return (
        <div></div>
   );
}
输出:
Header.js:23 rendering
Header.js:28 1
Header.js:29 false
Header.js:28 2
Header.js:29 false
Header.js:28 5
Header.js:29 false
Header.js:28 9
Header.js:29 false
Header.js:28 15
Header.js:29 false
Header.js:28 20
Header.js:29 false
Header.js:28 26
Header.js:29 false
Header.js:28 31
Header.js:29 false
Header.js:23 rendering
Header.js:28 35
Header.js:29 false
Header.js:23 rendering
Header.js:28 38
Header.js:29 false
Header.js:28 40
Header.js:29 false
Header.js:28 39
Header.js:29 false
Header.js:28 38
Header.js:29 false
Header.js:28 35
Header.js:29 false
Header.js:28 31
Header.js:29 false
Header.js:28 25
Header.js:29 false
Header.js:23 rendering
Header.js:28 20
Header.js:29 false
Header.js:23 rendering
Header.js:28 14
Header.js:29 false
Header.js:28 9
Header.js:29 false
Header.js:28 5
Header.js:29 false
Header.js:28 2
Header.js:29 false
Header.js:28 0
Header.js:29 false
我无法理解这种行为,为什么渲染被调用两次,并且即使滚动> = 30,FixedHeader也为false。
我是js的新手,所以我认为这是函数工作渲染存在2次的方式,因为函数被调用了两次,但是为什么两次,并且每次调用函数时都需要再次设置所有状态,这不会影响性能(我可能是错的)。
注意:我尚未添加html部分,这是简单的 header ,其中我基于 bool 变量添加了“fixed-top”类。

最佳答案

“渲染”显示两次的原因是因为您使用的是不同的条件。
对于类组件,您可以使用:

if (window.scrollY >= 25 && !this.state.fixed) {
    // ...
} else if (window.scrollY < 25 && this.state.fixed) {
    // ...
}
虽然功能组件使用:
if (window.scrollY >= 30) {
    // ...
} else {
    // ...
}
要解决此问题,您需要添加检查当前状态。
但是,就像您已经注意到的那样,检查FixedHeader值将始终导致相同的值(不会更新)。因此,我们需要首先解决该问题。
问题在于setFixedHeader不会在当前上下文中更新FixedHeader。它告诉React在下一个FixedHeader调用中使用传递的值作为新的Header重新渲染,但是当前上下文中的FixedHeader永远不会改变。
useEffect 允许您返回处理清理的函数。如果卸载了组件,或者在下一个useEffect调用之前(依赖项列表已更改),此函数将运行。将FixedHeader添加到依赖项列表将删除先前的滚动事件处理程序(使用返回的清理函数),并在FixedHeader值更改时使用新的FixedHeader值添加新的滚动事件处理程序。

const {useEffect, useState} = React;

const Header = props => {
    console.log("rendering");
    const [fixed, setFixed] = useState(false);

    useEffect(() => {
        const handleScroll = () => {
            console.log(window.scrollY);
            console.log(fixed);

            if (window.scrollY >= 30 && !fixed) {
                setFixed(true);
            } else if (window.scrollY < 30 && fixed) {
                setFixed(false);
            }
        };

        document.addEventListener("scroll", handleScroll);
        return () => document.removeEventListener("scroll", handleScroll);
    }, [fixed]);

    return null;
}

ReactDOM.render(<Header />, document.querySelector("#header-container"));
body { height: 1000px; }
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="header-container"></div>

关于javascript - React钩子(Hook)和React类之间的性能比较,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/63991545/

10-10 00:25