为啥 useEffect 不能在 return 语句中访问我的状态变量?
Posted
技术标签:
【中文标题】为啥 useEffect 不能在 return 语句中访问我的状态变量?【英文标题】:Why can't useEffect access my state variable in a return statement?为什么 useEffect 不能在 return 语句中访问我的状态变量? 【发布时间】:2020-09-09 09:36:45 【问题描述】:我不明白为什么我的useEffect()
React 函数无法访问我的组件的状态变量。当用户放弃在我们的应用中创建列表并导航到另一个页面时,我正在尝试创建日志。我正在使用 useEffect()
return
复制 componentWillUnmount()
生命周期方法的方法。你能帮忙吗?
代码示例
let[progress, setProgress] = React.useState(0)
... user starts building their listing, causing progress to increment ...
console.log(`progress outside useEffect: $progress`)
useEffect(() =>
return () => logAbandonListing()
, [])
const logAbandonListing = () =>
console.log(`progress inside: $progress`)
if (progress > 0)
addToLog(userId)
预期行为
代码将到达addToLog()
,导致此行为被记录。
观察到的行为
当用户在他们的列表中输入内容时会发生这种情况,导致 progress
增加,然后离开页面。
useEffect()
方法完美运行,并触发 logAbandonListing()
函数
第一个 console.log()
(useEffect
以上)记录了大于 0 的 progress
状态
第二个console.log()
为progress
状态记录0,禁用代码为if
语句返回true
并到达addToLog()
函数。
环境
使用在 Firefox 76.0.1 中运行的 Next.js 构建的应用的本地开发环境 nextjs v 8.1.0 反应 v 16.8.6我真的很感激能帮助我理解这里发生的事情。谢谢。
【问题讨论】:
【参考方案1】:我认为这是一个典型的陈旧关闭问题。而且一开始很难理解。
使用空依赖数组,useEffect 将只运行一次。它将从那一次运行中访问状态。所以从这一刻起它就会有来自 logAbandonListing 函数的引用。该函数也将从此时开始访问状态。您可以通过多种方式解决问题。
其中之一是将状态变量添加到您的依赖项中。
useEffect(() =>
return () => logAbandonListing()
, [progress])
另一种解决方案是将状态值设置为 ref。并且 ref 的引用没有改变,所以你总是会看到最新的值。
let[progress, setProgress] = React.useState(0);
const progressRef = React.createRef();
progressRef.current = progress;
...
const logAbandonListing = () =>
console.log(`progress inside: $progressRef.current`)
if (progressRef.current > 0)
addToLog(userId)
如果 userId 也发生了变化,那么您应该将其添加到依赖项或引用中。
【讨论】:
太棒了,谢谢,彼得。将变量作为依赖项添加到 useEffect() 调用很有效。 -“使用空的依赖数组,useEffect 将只运行一次。” 这让它在我的脑海中点击,非常感谢! 你好,希望你好,请你看看这个问题。非常感谢您的帮助。***.com/questions/65759907/… 我必须使用useRef
。对于createRef
,.current
似乎是只读的。【参考方案2】:
要在useEffect
的返回函数中的状态当前值中执行某些操作,其中useEffects
依赖项是空数组[]
,您可以使用useReducer
。这样您就可以避免过时的关闭问题并从useReducer
的dispatch
函数更新状态。
例如:
import React, useEffect, useReducer from "react";
function reducer(state, action)
switch (action.type)
case "set":
return action.payload;
case "unMount":
console.log("This note has been closed: " + state); // This note has been closed: 201
break;
default:
throw new Error();
function NoteEditor( initialNoteId )
const [noteId, dispatch] = useReducer(reducer, initialNoteId);
useEffect(function logBeforeUnMount()
return () => dispatch( type: "unMount" );
, []);
return <div>noteId</div>;
export default NoteEditor;
更多信息answer
【讨论】:
【参考方案3】:当你从useEffect
返回一个函数时,它的行为类似于componentWillUnmount
,所以我认为它只在清理时运行。您实际上需要致电logAbandonListing
,例如:
useEffect(() =>
logAbandonListing();
, []);
所以每次组件重新渲染时它都会运行。你可以在https://reactjs.org/docs/hooks-effect.html上阅读更多关于useEffect
的信息
写得真好。
【讨论】:
据我了解,这实际上调用 useEffect() 的方式反映了基于 React 类的组件中的 componentWillMount()。 logAbandonedListing() 之前的返回是关键,因为这会改变钩子的行为方式以镜像 componentWillUnmount(),这正是我在这里寻找的。span> 它反映了componentDidMount()
以及componentWillMount()
我认为&如果你返回它的行为就像componentWillUnmount()
。看到你找到了答案。典型的关闭。我也想过,但最后认为componentWillUnmount()
是个问题。
你好,希望你好,请你看看这个问题。非常感谢您的帮助。***.com/questions/65759907/…【参考方案4】:
我尝试使用这个沙盒来解释我的答案。 enter link description here
基本上你是从你的 useEffect 回调中返回一个函数。但是该返回的函数从未真正调用过,因此它实际上并没有执行,因此记录了放弃操作。如果您查看沙箱中的代码,我在之后添加了一个包装器 Parens 和 () 以实际导致调用该方法,从而导致执行 console.log。
【讨论】:
以上是关于为啥 useEffect 不能在 return 语句中访问我的状态变量?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在组件加载时不调用 useEffect(()=...,[]) ?