- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
当oldRunIn为undefined
时,下面代码的输出与触发效果时的预期一致:
Effect is running
setState is running
但是,下次 useEffect 运行时定义了状态变量 runInArrow
(在 setState 函数中称为 oldRunInArrow
),输出为:
Effect is running
setState is running
setState is running
setState is running
怎么可能effect只运行了一次而setState运行了3次?
const [runInArrow, setRunInArrow] = useState<mapkit.PolylineOverlay[] | undefined>(undefined);
useEffect(() => {
const trueRunIn = settings.magneticRunIn + magVar;
const boundingRegion = region.toBoundingRegion();
const style = new mapkit.Style({
lineWidth: 5,
lineJoin: 'round',
strokeColor: settings.runInColor,
});
const newRunInArrow = createArrow(boundingRegion, trueRunIn, style);
console.log('Effect is running');
setRunInArrow(oldRunIn => {
// This runs too many times when oldRunIn aka runInArrow is defined
console.log('setState is running');
if (oldRunIn) map.removeOverlays(oldRunIn);
return newRunInArrow;
});
map.addOverlays(newRunInArrow);
}, [magVar, map, mapkit, region, settings.magneticRunIn, settings.runInColor, settings.showRunIn]);
要了解为什么我使用函数来设置状态,请参阅此 post
<小时/>编辑:
这很奇怪。如果我删除 if (oldRunIn) map.removeOverlays(oldRunIn);
它会按预期工作。但是,如果我将其更改为 if (oldRunIn) console.log('oldRunIn is Defined'); ,它仍然会运行多次。我彻底糊涂了。
if (oldRunIn) map.addAnnotations([]);
不会运行多次。
if (oldRunIn) console.log('test');
确实运行了多次。
它总是运行多次(每个使用效果 6 次):
setRunInArrow(oldRunIn => {
console.log('setState is running');
console.log('test');
return newRunInArrow;
});
这不会运行多次:
setRunInArrow(oldRunIn => {
console.log('setState is running');
return newRunInArrow;
});
<小时/>
编辑2:
可重现的示例。单击按钮。您甚至不需要 if (oldState) console.log('Old state');
您只需放入第二个 console.log 即可更改行为。
import { FunctionComponent, useState, useEffect } from 'react';
export const Test: FunctionComponent<> = function Test() {
const [state, setState] = useState<number | undefined>(undefined);
const [triggerEffect, setTriggerEffect] = useState(0);
useEffect(() => {
console.log('effect is running');
setState(oldState => {
console.log('setState is runnning');
if (oldState) console.log('Old state');
return 1;
});
}, [triggerEffect]);
return <>
<button onClick={() => setTriggerEffect(triggerEffect + 1)} type="button">Trigger Effect</button>
</>;
};
<小时/>
编辑3:
我通过将此代码放入另一个 nextJS 项目中来重现此内容。我猜这与 nextJS 有关。
<小时/>编辑4:
这不是 NextJS。它将它包装在 React.StrictMode 中。这是sandbox 。为什么?
<小时/>编辑5:
正如答案所指出的,问题是由于 StrictMode 故意运行代码两次造成的。它不应该根据文档运行 useReducer 两次(这是我的其他问题中的“react-hooks/exhaustive-deps”的问题)。这是一个 UseReducer 演示,尝试使用和不使用 StrictMode。它还运行两次。看来它也需要纯净:
import { useState, useEffect, useReducer } from 'react';
function reducer(state, data) {
console.log('Reducer is running');
if (state) console.log(state);
return state + 1;
}
export const Test = function Test() {
const [state, dispatch] = useReducer(reducer, 1);
const [triggerEffect, setTriggerEffect] = useState(0);
useEffect(() => {
dispatch({});
}, [triggerEffect]);
return (
<>
<button onClick={() => setTriggerEffect(triggerEffect + 1)} type="button">
Trigger Effect
</button>
</>
);
};
const Home = () => (
<React.StrictMode>
<Test></Test>
</React.StrictMode>
);
export default Home;
最佳答案
正如您所发现的,当您使用 React 严格模式时就会发生这种情况,并且这是故意的。
如 this article 中所述:
It runs code TWICE
Another thing that React Strict Mode does is run certain callbacks/methods twice (in DEV mode ONLY). You read that right! The following callbacks/methods will be run twice in Strict Mode (in DEV mode ONLY):
- Class component constructor method
- The render method (includes function components)
- setState updater functions (the first argument)
- The static getDerivedStateFromProps lifecycle
- The React.useState state initializer callback function
- The React.useMemo callback
Checkout this codesandbox which logs to the console in hook callbacks and class methods to show you that certain things happen twice.
React 这样做是因为它无法可靠地警告您在这些方法中产生的副作用。但如果这些方法是幂等的,那么多次调用它们不会造成任何麻烦。如果它们不是幂等的,那么您应该注意到一些有趣的事情,您应该能够注意到并修复这些事情。
Note that useEffect and useLayoutEffect callbacks are not called twice even in dev mode + strict mode because the entire point of those callbacks is to perform side-effects.
Note that I also observed that the reducer you pass to React.useReducer is not called twice in dev mode. I'm not sure why this is because I feel like that could also benefit from this kind of warning.
如上所示,包含此行为是为了帮助您查找代码中的错误。由于更新程序函数应该是幂等且纯粹的,因此运行它们两次而不是一次应该不会对应用程序的功能产生影响。如果确实如此,那么这就是您的代码中的错误。
听起来像
map.removeOverlays()
您调用的方法是一个有效的函数,因此不应在状态更新器函数中调用它。根据 your other question 的答案,我可以明白为什么您要以这种方式实现它,但我认为使用 chitova263 的答案可以解决这个问题。
关于javascript - React.StrictMode : SetState function in useEffect is run multiple times when effect is run once,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60305074/
我知道没有数组的 useEffect() 只在第一次渲染时运行回调。 那么useEffect(()=>{},[])和没有useEffect()的区别是什么。 我的意思是: function myCom
我的场景很少,我想了解渲染和性能方面的差异。 下面显示的示例是一个简单的函数,但请考虑一个更复杂的函数以及一个异步函数。 场景 1:定义函数并在 useEffect 中调用它。 useEffect((
我需要添加一些与 React 之外的对象交互的事件处理程序(以 Google map 为例)。 在这个处理函数内部,我想访问一些可以发送给这个外部对象的状态。 如果我将状态作为依赖项传递给效果,它可以
要限制 useEffect 在第一个渲染上运行,我们可以这样做: const isFirstRun = useRef(true); useEffect (() => { if (isF
我有一个产品组件,它显示某个类别的产品。CategoryId 从路由参数中获取,然后用户可以对产品进行分页。所以有2个useEffect,一个是改变categoryId的时候,另一个是改变当前页码的时
我有一个产品组件,它显示某个类别的产品。CategoryId 从路由参数中获取,然后用户可以对产品进行分页。所以有2个useEffect,一个是改变categoryId的时候,另一个是改变当前页码的时
我的状态宽度随着窗口大小的调整而变化,showFilters作为 Prop 从true变为false。我想在卸载时删除监听器。因此,我为每个条件使用了三个 useState。那么,我可以做任何重构来在
我正在开发一个基于对象键管理字符串数组的函数。假设它看起来像这样: import React, { useState, useEffect } from "react"; import FieldCo
新的 React Hooks 功能很酷,但有时会让我感到困惑。特别是,我将此代码包装在 useEffect Hook 中: const compA = ({ num }) => { const [
我想将其转换为 useEffect钩: 代码 componentDidMount () { this.messagesRef.on('child_added', snapshot => {
这是我的代码部分。一切正常,但 eslint 给出错误。 React Hook useEffect has missing dependencies: 'dispatch' and 'getData'
当组件安装时,我需要从两个 API 端点获取数据。现在我有: useEffect(() => { dispatch(loadSomeDataOne()); }, [dispatch])
当组件安装时,我需要从两个 API 端点获取数据。现在我有: useEffect(() => { dispatch(loadSomeDataOne()); }, [dispatch])
在 React DOCs 中,关于 useEffect() 钩子(Hook),我们得到: “使用 useEffect 安排的效果不会阻止浏览器更新屏幕。” Tip Unlike componentDi
我一直试图了解何时取消订阅(useEffect 中的回调)被准确调用。 这是codepen链接:https://codepen.io/deen_john/pen/eYmNdMy 代码 : const
当对状态、效果、上下文等使用钩子(Hook)时,我这样做: import React, { useState, useEffect, useContext } from 'react'; 但是,我注意
我正在尝试像下面这样的 useEffect 示例: useEffect(async () => { try { const response = await fetch(`ht
我在我的 React 应用中构建了一个简单的点赞、书签功能。 const [liked, setLiked] = useState(); const [bookmarked, setBookmarke
我想了解为什么在代码块的底部使用 useEffect,以及它的用途。我认为它与组件生命周期和避免无限循环有关,但我无法完全理解它并全面了解这一切。如果有人能向我解释幕后发生的事情,以及 useEffe
useEffect(() => { return history.replace({ pathname: "path/A", }); }, []); useEffe
我是一名优秀的程序员,十分优秀!