React:从回调访问时,State 内部的数组未定义

问题描述 投票:0回答:1

我有一个回调函数,它应该编辑数组中的值,该数组位于状态内部。当我尝试访问

dataZähler
时,即数组本身,我得到了长度为 0 的未定义/数组。这是为什么?

有问题的代码(希望减少到最基本的必要性):

'use client'
import { useCallback, useEffect, useState } from "react";
import { ProtokollEintrag, TogglePosition, ZählerCallback, ZählerObjekt } from "./dataTypes";
import { ToggleButton, ToggleButtonGroup, Divider, ZoomProps } from "@mui/material";
import ElectricalServicesIcon from '@mui/icons-material/ElectricalServices';
import clsx from "clsx";
import { Modal } from "react-bootstrap";
import { CreateCounterPopUp, CreateEntryPopUp, EditCounterPopUp, EditEntryPopUp, CalculateDeltaPopUp } from "./pages/myPopups";

export default function Home() {
  //data and internal logic states, table-content, which rows are selected, is the data still loading, etc.
  const [loading, setLoading] = useState(true);
  const [dataZähler, setDataZähler] = useState<ZählerObjekt[]>([]);
  const [dataProtokoll, setDataProtokoll] = useState<ProtokollEintrag[]>([]);
  const [selectedRowZähler, setSelectedRowZähler] = useState(-1);
  const [selectedRowProtokoll, setSelectedRowProtokoll] = useState(-1);
  //View-Logic states, which table is shown, if modals should be seen, etc
  const [showEditZählerModal, setShowEditZählerModal] = useState(false);

  //on start, load both csv's into states
  useEffect(() => {
    fetch('/api/loadCsv')
      .then((res) => res.json())
      .then((data) => {
        setDataZähler(data.dataZähler)
        setDataProtokoll(data.DataProtokoll)
        setLoading(false)
      })
  }, []);

  function handleEditZähler() {
    if (currentTable === TogglePosition.Zähler && selectedRowZähler >= 0) {
      setShowEditZählerModal(true);
    }
  };

  const handleEditZählerCallback: ZählerCallback = useCallback((data: ZählerObjekt | null) => {
    console.log(dataZähler);
    if (data) {
      const oldData = dataZähler.map((elem, idx) => {
        if (idx === selectedRowZähler)
          return { ...data };
        return elem;
      });
      console.log(data);
      console.log(oldData);
      setDataZähler(oldData);
      setSelectedRowZähler(-1);
    }
    setShowEditZählerModal(false);
  }, []);

  return (
    <div className="flex flex-col">
      {/* Buttons und Toggle zur Verwendung und Steuerung des Interfaces */}
      <div className="justify-center flex sticky bottom-0 space-x-4 bg-[white] bg-opacity-60">
      <button onClick={handleEditZähler} disabled={selectedRowZähler < 0} className={clsx("bg-[#0ea5e9] border-[none] text-[white] text-center inline-block text-base rounded-[5px] px-5 py-3 my-2", { "bg-[#d1d5db]": selectedRowZähler < 0 })}>Bearbeiten</button>
      </div>
      {/*Modal Div - all edit/Cancel/Save/Create/Delete modals go here*/}
      <div>
        <Modal size="lg" show={showEditZählerModal} onHide={() => setShowEditZählerModal(false)}>
          <Modal.Header closeButton>
            <Modal.Title>
              Zähler Bearbeiten:
            </Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <EditCounterPopUp data={dataZähler[selectedRowZähler]} callback={handleEditZählerCallback} />
          </Modal.Body>
        </Modal>
      </div>
    </div>
  );
}

如果它很重要,这里是编辑 ZählerObjekt 的模式:

import { ChangeEvent, FormEvent, useState } from "react";
import { ZählerObjekt, ProtokollEintrag, ZählerCallback, EintragCallback } from "../dataTypes";
import { Form } from "react-bootstrap";
import { generateGenericObjectID } from "../util/objectIdentifier";

interface CounterProps {
    data: ZählerObjekt,
    callback: ZählerCallback
}

export function EditCounterPopUp({ data, callback }: CounterProps) {
    const [newCounter, setNewCounter] = useState({ ...data });

    function handleSpeichern(event: React.MouseEvent<HTMLButtonElement>) { //dont forget to set the id of the new object
        event.preventDefault();
        setNewCounter({ ...newCounter, ...{ id: generateGenericObjectID(newCounter) } });
        callback(newCounter);
    }

    function handleInputChange(field: string, event: ChangeEvent<HTMLInputElement>) {
        const newState = { ...newCounter };
        newState[field as keyof ZählerObjekt] = event.target.value;
        setNewCounter(newState);
    }

    return (
        <div>
            <form>
                {Object.entries(newCounter).slice(1).map((elem, idx) => {
                    return (
                        <Form.Group
                            className="mb-3" key={idx} controlId={elem[0]}
                        >
                            <Form.Label>{elem[0]}</Form.Label>
                            <Form.Control
                                as="textarea"
                                rows={2}
                                placeholder={"z.B. " + String(data[elem[0] as keyof ZählerObjekt])}
                                value={elem[1]}
                                onChange={(e) => handleInputChange(elem[0], e as any)} />
                        </Form.Group>
                    );
                })}
                <div className="float-right">
                    <button onClick={handleSpeichern} className="bg-[#22c55e] border-[none] text-[white] text-center inline-block text-base rounded-[5px] px-5 py-3 my-2">Speichern</button>
                </div>
            </form>
        </div>
    );
}

为什么回调中

dataZähler
是unedfined?我该如何解决这个问题?

javascript reactjs next.js bootstrap-modal
1个回答
0
投票

问题是一个空的依赖数组。将

dataZähler
selectedRowZähler
包含在
useCallback
的依赖数组中。检查下面的代码:

const handleEditZählerCallback: ZählerCallback = useCallback((data: ZählerObjekt | null) => {
  if (data) {
    const oldData = dataZähler.map((elem, idx) => {
      if (idx === selectedRowZähler)
        return { ...data };
      return elem;
    });
    setDataZähler(oldData);
    setSelectedRowZähler(-1);
  }
  setShowEditZählerModal(false);
}, [dataZähler, selectedRowZähler]);

依赖项数组 [dataZähler, selectedRowZähler] 确保每次更改时回调都具有这些依赖项的最新值。如果没有这个,回调可能会使用 dataZähler 和 selectedRowZähler 的陈旧值。

© www.soinside.com 2019 - 2024. All rights reserved.