- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我尝试将基于类的组件更改为功能组件,但当我尝试读取附加有 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/
createHiveBackground 函数返回我要分配给状态的对象数组。稍后在我的应用程序中,我将使用 setHive 来更改数组的一些值。这些有什么区别? const [hive, setHiv
我很好奇为什么这么多程序员单独导入useState。 import React, { useState } from 'react'; const [foo, setFoo] = useState('
我已经设置了最基本的示例,即TODO列表当我第一次单击Done按钮时,它按预期工作:TODO项被标记为Done:True,并且“Fire”和“Setting”只触发一次。从那时起,我单击的任何按钮都会
我已经设置了最基本的示例,即TODO列表当我第一次单击Done按钮时,它按预期工作:TODO项被标记为Done:True,并且“Fire”和“Setting”只触发一次。从那时起,我单击的任何按钮都会
我正在尝试构建一个可以或不能接收查询字符串的代码。如果它收到所有查询字符串,我想执行一个函数: // state for query const [query, setQuery] = use
下面的代码有什么问题吗?使用 useState 时,我收到 typescript 警告 import * as React, { useState } from 'react' const useFo
我对此的反应是新的。我用每个开关元素创建了一个项目数组,问题是:当我单击一个项目时,所有项目都会同时激活!。我尝试了许多通过搜索找到的解决方案,但都不起作用。
我对此的反应是新的。我用每个开关元素创建了一个项目数组,问题是:当我单击一个项目时,所有项目都会同时激活!。我尝试了许多通过搜索找到的解决方案,但都不起作用。
我希望我没有重复一个问题。我看过这个:TypeError dispatcher.useState is not a function when using React Hooks ,但是我的应用程序运
当对状态、效果、上下文等使用钩子(Hook)时,我这样做: import React, { useState, useEffect, useContext } from 'react'; 但是,我注意
所以我试图在我的 nextjs 应用程序中使用 useState,但是一旦我添加了代码行来初始化 useState,它就会抛出一个带有错误消息的弹出错误:TypeError: Cannot read
我在单击表单提交按钮时使用 React useState 钩子(Hook)更新状态,直到第二次单击时状态才会更新。相信我需要使用 useEffect 但不确定如何使用 onClick 来实现。 con
是否可以从子组件内部更改 useState 的值? 家长: const [state, setState] = useState(false); return setState(true)}/> c
useState 不会立即更新状态。 我正在使用 react-select并且我需要根据请求的结果使用选择的 (multi) 选项加载组件。 出于这个原因,我创建了状态 defaultOptions
这个问题在这里已经有了答案: The useState set method is not reflecting a change immediately (15 个回答) 2年前关闭。 这是所有新
我想在触发正常函数 (handleConsultantChange) 后使用 useState 函数 (setFilterConsultantId) 更改状态 (filterConsultantId)
这是组件的完整代码,我累得想不出怎么解决这个问题 import React, { useEffect, useState } from 'react'; import { Link } from 'r
我正在尝试初始化一个常量变量,它可以用作字符串或字符串数组,具体取决于我的组件正在接收的 Prop 。 我正在尝试将其初始化为 const [selectedOptions, setSelecte
我有两个组件,一个放在另一个里面。子组件打印父组件传递的状态,并使用 useEffect 更新一次状态。在父组件中,我使用 setState(具有 bool 值的对象)并将状态传递给所有子组件。 父组
我们知道useState是FC中的一个hook,返回一个由两个元素组成的数组。第一个是状态变量,第二个是更新状态变量的函数。 const initialStateVariableValue = 0;
我是一名优秀的程序员,十分优秀!