简体   繁体   English

State 即使在 useEffect 中设置后也返回一个空数组

[英]State returns an empty array even after setting in useEffect

I have seen similar questions on SO but have not been able to identify the issue I'm having.我在 SO 上看到过类似的问题,但无法确定我遇到的问题。

I have a useState variable that I set in useEffect on first load.我有一个 useState 变量,我在第一次加载时在 useEffect 中设置。 Then, at a much later time an event fires and within the event I check the value of the variable and it's always an empty array [].然后,在很久以后一个事件触发并且在事件中我检查变量的值,它总是一个空数组[]。 However, I added a second useEffect to track the changes in my state variable and I don't see where it's being emptied.但是,我添加了第二个 useEffect 来跟踪我的 state 变量的变化,我看不到它在哪里被清空。 Here's some code to highlight my issue:这是一些代码来突出我的问题:

import React, { useState, useEffect } from "react";
import { DragAndDrop } from "../components";

const AddKidPage = () => {
  const [files, setFiles] = useState([]);

  useEffect(() => {
    var f = [
      "nice.pdf",
      "verycool.jpg",
      "amazing.png",
      "goodstuff.mp3",
      "thankyou.doc",
    ];

    setFiles(f);
  }, []);

  useEffect(() => {
    console.log(files);
  }, [files]);

  const handleDrop = (newFiles) => {
    let fileList = files;

    // HERE FILES = []

    for (var i = 0; i < newFiles.length; i++) {
      if (!newFiles[i].name) return;
      fileList.push(newFiles[i].name);
    }

    setFiles(fileList);
  };

  return (
    <main>
      <DragAndDrop handleDrop={handleDrop}>
        <div style={{ height: 300, width: 250 }}>
          {files.map((file, i) => (
            <div key={i}>{file}</div>
          ))}
        </div>
      </DragAndDrop>
    </main>
  );
};

export default AddKidPage;

I have 1 console.log in the file-tracking useEffect.我在文件跟踪useEffect中有1个console.log。 Here is the output when the component mounts:这是安装组件时的 output:

[] []

["nice.pdf", "verycool.jpg", "amazing.png", "goodstuff.mp3", "thankyou.doc"] [“nice.pdf”、“verycool.jpg”、“amazing.png”、“goodstuff.mp3”、“thankyou.doc”]

This makes sense - I'm initializing the array as empty then I immediately fill it with values which then triggers the second output.这是有道理的——我将数组初始化为空,然后立即用值填充它,然后触发第二个 output。 However, here is the output AFTER I drop a file (this causes handleDrop() to execute):但是,这里是 output 在我删除文件之后(这会导致 handleDrop() 执行):

["newFile.png"] [“新文件.png”]

As you can see ALL other values were wiped out.如您所见,所有其他值都被清除了。 My comment in code "HERE FILES = []" demonstrates where the files useState is still empty even though my output shows it was filled.我在代码“HERE FILES = []”中的注释演示了文件 useState 仍然为空的位置,即使我的 output 显示它已被填充。 The useEffect never outputs an empty array a second time so where is it being emptied? useEffect 永远不会第二次输出一个空数组,那么它在哪里被清空? Am I retrieving the value wrong?我检索值错误吗? Any help with this mystery is greatly appreciated.非常感谢您对这个谜团的任何帮助。 I opted to not show the code for DragAndDrop component but it seems solid and calls the handleDrop method at the right time and with correct values.我选择不显示 DragAndDrop 组件的代码,但它看起来很可靠,并在正确的时间以正确的值调用了 handleDrop 方法。

EDIT:编辑:

Although DragAndDrop seems solid, this could be some sort of issue with how I'm calling the passed in function... or my use of {children}.尽管 DragAndDrop 看起来很可靠,但这可能是我如何调用传入的 function ... 或我使用 {children} 的某种问题。 I'm not sure.我不确定。 So, here is the code for DragAndDrop which completes this component.所以,这里是完成这个组件的 DragAndDrop 的代码。


import React, { useState, useEffect } from "react";
import styled from "styled-components";

const DragAndDrop = ({ handleDrop: externalDrop, children }) => {
  const [drag, setDrag] = useState(false);
  const [dragCounter, setDragCounter] = useState(0);

  const handleDrag = (e) => {
    e.preventDefault();
    e.stopPropagation();
  };

  const handleDragIn = (e) => {
    e.preventDefault();
    e.stopPropagation();

    setDragCounter(dragCounter + 1);
    if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
      setDrag(true);
    }
  };

  const handleDragOut = (e) => {
    e.preventDefault();
    e.stopPropagation();

    setDragCounter(dragCounter - 1);
    if (dragCounter - 1 === 0) {
      setDrag(false);
    }
  };

  const handleDrop = (e) => {
    e.preventDefault();
    e.stopPropagation();

    setDrag(false);
    if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
      externalDrop(e.dataTransfer.files);
      e.dataTransfer.clearData();
      setDragCounter(0);
    }
  };

  useEffect(() => {
    var div = document.getElementById("draganddrop-wrapper");

    div.addEventListener("dragenter", handleDragIn);
    div.addEventListener("dragleave", handleDragOut);
    div.addEventListener("dragover", handleDrag);
    div.addEventListener("drop", handleDrop);

    return () => {
      div.removeEventListener("dragenter", handleDragIn);
      div.removeEventListener("dragleave", handleDragOut);
      div.removeEventListener("dragover", handleDrag);
      div.removeEventListener("drop", handleDrop);
    };
  }, []);

  return (
    <Wrapper id="draganddrop-wrapper">
      {drag && (
        <div className="drag-hover">
          <div className="drag-overlay">
            <div>drop here</div>
          </div>
        </div>
      )}
      {children}
    </Wrapper>
  );
};

const Wrapper = styled.div`
  display: inline-block;
  position: relative;
  .drag-hover {
    border: dashed grey 4px;
    background: rgba(255, 255, 255, 0.8);
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 9999;
    .drag-overlay {
      position: absolute;
      top: 50%;
      right: 0;
      left: 0;
      text-align: center;
      color: grey;
      font-size: 36px;
    }
  }
`;

export default DragAndDrop;


Its because you are mutating the files variable instead of cloning it.这是因为您正在改变files变量而不是克隆它。

Change改变

let fileList = files;

to

const fileList = [...files];

Update更新

const handleDrop = useCallback((newFile) => {
    if (newFile.type === "image/png") {
        setFile(newFile.name);
    }
}, []);

Codesandbox 代码沙盒

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM