Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/469.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么AddEventListener上的回调打印旧状态?_Javascript_Reactjs - Fatal编程技术网

Javascript 为什么AddEventListener上的回调打印旧状态?

Javascript 为什么AddEventListener上的回调打印旧状态?,javascript,reactjs,Javascript,Reactjs,我有一个回调函数,在其中我设置了一些状态。国家似乎发生了变化。但是,我不能在回调函数中引用更新的状态-它总是打印出初始状态 所以我的问题是为什么会发生这种情况,如果我想检查回调中的更新状态,我应该如何继续 import React, { useState, useEffect } from "react"; import Context from "./ctx"; export default props => { const [state, setState] = useState

我有一个回调函数,在其中我设置了一些状态。国家似乎发生了变化。但是,我不能在回调函数中引用更新的状态-它总是打印出初始状态

所以我的问题是为什么会发生这种情况,如果我想检查回调中的更新状态,我应该如何继续

import React, { useState, useEffect } from "react";
import Context from "./ctx";

export default props => {
  const [state, setState] = useState({
    x: 0,
    y: 0
  });

  useEffect(() => {
    window.addEventListener("resize", e => {
      setState({
        x: e.target.window.visualViewport.width,
        y: e.target.window.visualViewport.height
      });
      console.log(`${JSON.stringify(state)}`); <<---logs the initial state.
    });

    return () => {
      window.removeEventListener("resize");
    };
  }, []);

  console.log(`${JSON.stringify(state)}`); <<---logs updated versions of the state.

  return (
    <Context.Provider
      value={{
        ...state
      }}
    >
      {props.children}
    </Context.Provider>
  );
};
import React,{useState,useffect}来自“React”;
从“/ctx”导入上下文;
导出默认道具=>{
常量[状态,设置状态]=使用状态({
x:0,,
y:0
});
useffect(()=>{
window.addEventListener(“调整大小”,e=>{
设定状态({
x:e.target.window.visualViewport.width,
y:e.target.window.visualViewport.height
});

console.log(`${JSON.stringify(state)}`)javascript闭包中的原因。
useffect
回调有一个旧版本的数据,因为deps数组为空,外部数据不会更新。因此使用了旧版本的
state
对象。这就是为什么得到相同的值的原因。

SetState是异步的,在执行该行代码后,您将得到旧值,o您可以做的一件事是侦听要更新的状态,然后在该效果中输出console.log,例如:

useffect(()=>{
console.log(`${JSON.stringify(state)}`);//{
console.log(`${JSON.stringify(state)}`);//{
设定状态({
x:e.target.window.visualViewport.width,
y:e.target.window.visualViewport.height
});
控制台日志(“更新”);
});
return()=>{
removeEventListener(“调整大小”,处理程序);
};
}, []);

console.log(`${JSON.stringify(state)}`);//您面临的问题与两件事有关:

  • React是如何工作的
  • 闭包(创建闭包的函数+环境)
  • 1.React是如何工作的

    您已经创建并导出了功能性React组件,它接受一些道具,使用钩子进行状态管理,并呈现一些内容。 当组件(或其父组件)中的某些道具或状态更改发生反应时,将重新呈现组件,这意味着:它将直接调用您的函数,如
    yourComponent(props)
    。 要点是:每次重新渲染时都会执行函数体,同时调用
    useState
    useffect

    2.闭包(创建闭包的函数+环境)

    每当我们在JavaScript中创建/定义某个函数时,它都与创建它的环境一起存储在运行时内存中。 在您的例子中,您在这里定义了有问题的函数(同时将其作为
    useffect
    的回调提供):

    ()=>{
    window.addEventListener(“调整大小”,e=>{
    设定状态({
    x:e.target.window.visualViewport.width,
    y:e.target.window.visualViewport.height
    });
    
    console.log(`${JSON.stringify(state)}`);useState是异步函数。在更新后尝试访问它时,它不能是最新的。您可以添加一个新的useEffect回调,其状态为数组参数:
    useEffect(=>console.log(state),[state]))
    @demkovych是正确的,因为状态更新程序是异步的,所以在下一次渲染之前,不能假定状态已经更新
    useEffect(() => {
        window.addEventListener("resize", e => {
          setState({
            x: e.target.window.visualViewport.width,
            y: e.target.window.visualViewport.height
          });
          console.log(`${JSON.stringify(state)}`);
        });
    
        return () => {
          window.removeEventListener("resize");
        };
      }, []); // <-- HERE 
    
    useEffect(() => {
        window.addEventListener("resize", e => {
          setState({
            x: e.target.window.visualViewport.width,
            y: e.target.window.visualViewport.height
          });
          console.log(`${JSON.stringify(state)}`); 
        });
    
        return () => {
          window.removeEventListener("resize");
        };
      }, [state]); // <-- NOW THE CALLBACK WILL BE EXECUTED EVERY TIME STATE CHANGES
    
    useEffect(() => {
        window.addEventListener("resize", e => {
          setState({
            x: e.target.window.visualViewport.width,
            y: e.target.window.visualViewport.height
          });
          console.log(`${JSON.stringify(state)}`);
        });
    
        return () => {
          window.removeEventListener("resize");
        };
      }); // <-- WITHOUT SECOND ARGUMENT