gpt4 book ai didi

javascript - 功能组件中 useEffect() 内的 useState()

转载 作者:行者123 更新时间:2023-11-28 14:14:55 25 4
gpt4 key购买 nike

我尝试将基于类的组件更改为功能组件,但当我尝试读取附加有 useEffect() 的处理函数内的状态属性时遇到了麻烦

在基于类的组件内,我将在 componentDidMount 中附加处理程序方法,并且该处理程序可以访问状态。

渲染的输出确实在两种类型的组件中显示了正确的值!

但是当我需要处理程序中状态属性的当前值来计算新状态值时,我在读取状态属性时遇到了麻烦内部功能组件。

我创建了以下示例来演示该问题:https://codesandbox.io/s/peaceful-wozniak-l6w2c (打开控制台并滚动)

如果您单击组件,则两个组件都可以正常工作:

  • 控制台输出状态属性的当前值计数器
  • 增加状态属性计数器

如果仅滚动基于类的组件有效:

  • 控制台输出状态属性position的当前值
  • 更新状态属性位置

但是功能组件的控制台输出只返回我初始状态属性值。

基于类的组件

import React, { Component } from "react";

export default class CCTest extends Component {
constructor(props) {
super(props);
this.state = { position: 0, counter: 0 };
this.handleScroll = this.handleScroll.bind(this);
this.handleClick = this.handleClick.bind(this);
}

handleScroll(e) {
console.log(
"class.handleScroll()",
this.state.position
);
this.setState({ position: document.body.getBoundingClientRect().top });
}

handleClick() {
console.log("[class.handleClick]", this.state.counter);
this.setState(prevState => ({ counter: prevState.counter + 1 }));
}

componentDidMount() {
window.addEventListener("scroll", this.handleScroll);
}

render() {
return (
<div
style={{
backgroundColor: "orange",
padding: "20px",
cursor: "pointer"
}}
onClick={this.handleClick}
>
<strong>class</strong>
<p>
position: {this.state.position}, counter: {this.state.counter}
</p>
</div>
);
}
}

功能组件

import React from "react";

export default prop => {
const [position, setPosition] = React.useState(0);
const [counter, setCounter] = React.useState(0);

React.useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
// eslint-disable-next-line
}, []);

const handleScroll = () => {
console.log(
"function.handleScroll()",
position
);
setPosition(document.body.getBoundingClientRect().top);
};

const handleClick = () => {
console.log("[function.handleClick]", counter);
setCounter(counter + 1);
};

return (
<div
style={{ backgroundColor: "green", padding: "20px", cursor: "pointer" }}
onClick={handleClick}
>
<strong>function</strong>
<p>
position: {position}, counter: {counter}
</p>
</div>
);
};

每个小提示都有帮助<3

最佳答案

每次渲染组件时,都会创建一个新的 handleScroll 函数,该函数可以通过组件闭包访问当前状态。但这个闭包不会在每次渲染时更新;相反,会创建一个新的 handleScroll 函数,该函数会看到新值。

问题是当你这样做时:

window.addEventListener("scroll", handleScroll);

您将函数的当前版本绑定(bind)到事件,并且它将始终读取当时的值,而不是新值。通常,useEffect 将再次运行并使用该函数的新实例,但您使用空数组作为第二个参数来阻止它。

仅针对这些情况有一个 linter 警告,但您已禁用它:

// eslint-disable-next-line

如果删除这个空数组,则可以删除 linter 禁用规则,并且它将正常工作。

其他选项

当不能每次都更改函数时(例如,使用非 React 库时,或出于性能原因),还有其他选择:

  • 您可以使用ref而不是状态。引用会发生变化,而不是在每次渲染时创建新的引用。这允许该函数的早期版本读取当前值并修改它,即使您不更新该函数也是如此。

  • 您可以使用useReducer 。调度函数永远不会改变,所以如果你的 useEffect 依赖于它,它不会被重新运行。 reducer 可以访问先前的值和操作,因此即使它依赖于先前的状态,它也可以计算新的状态。

关于javascript - 功能组件中 useEffect() 内的 useState(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57886384/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com