【问题标题】: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

我真的很感激能帮助我理解这里发生的事情。谢谢。

【问题讨论】:

    标签: reactjs next.js use-effect


    【解决方案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 将只运行一次。” 这让它在我的脑海中点击,非常感谢!
    • 你好,希望你好,请你看看这个问题。非常感谢您的帮助。stackoverflow.com/questions/65759907/…
    • 我必须使用useRef。对于createRef.current 似乎是只读的。
    【解决方案2】:

    要在useEffect 的返回函数中的状态当前值中执行某些操作,其中useEffects 依赖项是空数组[],您可以使用useReducer。这样您就可以避免过时的关闭问题并从useReducerdispatch 函数更新状态。

    例如:

    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() 是个问题。
      • 你好,希望你好,请你看看这个问题。非常感谢您的帮助。stackoverflow.com/questions/65759907/…
      【解决方案4】:

      我尝试使用这个沙盒来解释我的答案。 enter link description here

      基本上你是从你的 useEffect 回调中返回一个函数。但是该返回的函数从未真正调用过,因此它实际上并没有执行,因此记录了放弃操作。如果您查看沙箱中的代码,我在之后添加了一个包装器 Parens 和 () 以实际导致调用该方法,从而导致执行 console.log。

      【讨论】:

        猜你喜欢
        • 2020-07-14
        • 2020-10-09
        • 1970-01-01
        • 1970-01-01
        • 2020-11-28
        • 1970-01-01
        • 2012-12-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多