为什么我的 React/Javascript 事件不起作用?

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

我正在编写一个带有任务显示页面的自动化即服务前端(开源)。我已经对其进行了所有常见的调试,并发现问题似乎出在 onChange 处理程序上,主要是从消除过程中得出的,而且还在整个代码中使用了调试语句,而且它甚至没有进入处理程序事件函数。所以,这并不是说 Web 组件被阻止或发生任何事情(除了很可能被其他事件阻止)。

引入错误是因为我在这个页面添加了流程。最初,该页面有一个请求文件上传的按钮。页面上的表格采用 JSON 或 YAML 文件,并将该文件中将发生的任务列出到表格中,以便可以查看和编辑它们。一切都很好。行显示在表格中。

然后,我有了一个绝妙的主意,安装 dJango_eventstream 和 daphne 来启用服务器端事件,这样我就可以显示一个对话框,说明导入文件时发生的情况,而不是让用户耐心等待一分钟(没有用户有耐心)。这破坏了它,但破坏似乎是由于向页面添加多个新事件来处理导入对话框窗口和 SSE 事件。按钮代码和其他所有内容之前都可以正常工作。我重写了事件处理程序,以更简洁的方式组合事物,但没有成功。

我坦白承认,我是这里的Python开发人员。这是我的第一个 React 项目和第一个 JavaScript 项目,所以我不知道我在做什么。我可以想办法解决,因为它与我所知道的相似,但总的来说,javascript 事件远远超出了我的理解范围。我可能对这里的各个概念有所了解,然后在尝试将它们结合起来时完全失败了。

有问题的代码(删除表设置以使其变小):

import React, { useState, useEffect } from 'react';
import { DataGrid } from '@mui/x-data-grid';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import Copyright from '../internals/components/Copyright';
import axios from 'axios';
import ImportDialog from './importDialog';

const API_URL = 'http://backend:8000/';


const callRestApi = (endpoint, method = 'GET', body) => {
  const sessionToken = window.sessionStorage.getItem('sessionToken');

  const headers = {
    'Accept': 'application/json',
  };

  if (sessionToken) {
    headers['Authorization'] = `Token ${sessionToken}`;
  } else {
    console.warn('No session token found in storage. This request might fail if authorization is required.');
  }

  return axios({
    method,
    url: `${API_URL}/${endpoint}`,
    data: body,
    headers,
  }).catch(err => {
    console.error('Request failed:', err);
  });
};

export default function Tasks() {
  const [tasks, setTasks] = useState([]);
  const [selectedFile, setSelectedFile] = useState(null);
  const [dialogOpen, setDialogOpen] = useState(false);
  const [importResults, setImportResults] = useState('');

  useEffect(() => {
    callRestApi("tasks/", 'GET', null).then((res) => {
      if (res && res.data) {
        setTasks(res.data);
      } else {
        console.error("Failed to load tasks data.");
      }
    });
  }, []);

  const handleFileChange = (event) => {
    alert("Handle File Change");
    const file = event.target.files[0];
    if (file) {
      setSelectedFile(file);
      handleFileUpload(file);
    }
    event.target.value = ''; // reset the file input
  };

  const handleFileUpload = async (file) => {
    if (!file) {
      alert("Please select a file first.");
      return;
    }

    const formData = new FormData();
    formData.append('file', file);
    try {
      const uploadResponse = await axios.post(`${API_URL}api/tasks/api_upload/`, formData, {
        headers: { 'Content-Type': 'multipart/form-data' }
      });
      console.log('File uploaded:', uploadResponse.data);

      // Start SSE after upload
      const eventSource = new EventSource(`${API_URL}/events/import/`);
      const messages = [];

      eventSource.onmessage = (event) => {
        const data = JSON.parse(event.data);
        messages.push(data.text);
        setImportResults(messages.join("\n"));
        setDialogOpen(true);
      };

      eventSource.onerror = (error) => {
        console.error('SSE error:', error);
        eventSource.close();
      };
    } catch (error) {
      console.error('Error uploading file:', error);
    }
  };
  
  const handleDialogClose = () => {
    setDialogOpen(false);
  };

  return (
    <Box sx={{ width: '100%', maxWidth: { sm: '100%', md: '1700px' } }}>
      <Box sx={{ width: '100%', maxWidth: { sm: '100%', md: '1700px' } }}>
        <Typography color="blue" component="h2" variant="h6" sx={{ mb: 2 }}>
          Tasks
        </Typography>
        <input
          type="file"
          onChange={handleFileChange}
          accept=".yaml,.json"
          id="file-input"
          style={{ display: 'none' }}
        />
        <Button
          variant="contained"
          startIcon={<CloudUploadIcon />}
          onClick={() => {
            document.getElementById('file-input').click();
          }}
        >
          Upload API Definition
        </Button>
      </Box>

      <Box sx={{ width: '100%', maxWidth: { sm: '100%', md: '1700px' } }}>
        <DataGrid
          autoHeight
          checkboxSelection
          columns={columns}
          rows={tasks}
          getRowClassName={(params) =>
            params.indexRelativeToCurrentPage % 2 === 0 ? 'even' : 'odd'
          }
          initialState={{
            pagination: { paginationModel: { pageSize: 20 } },
          }}
          pageSizeOptions={[10, 20, 50]}
          density="compact"
        />
        <Copyright sx={{ my: 4 }} />
      </Box>

      {/* Import Dialog */}
      <ImportDialog
        open={dialogOpen}
        handleClose={handleDialogClose}
        importResults={importResults}
      />
    </Box>
  );
}
  1. 我尝试手动触发按钮,只有当我将事件函数直接放在按钮的 onClick 事件中时才有效。它不会以正确的方式工作,这也表明事件没有触发。

  2. 我尝试将按钮移动到另一个位置,看看主题是否挡住了它,但没有成功。

  3. 我尝试取出除按钮定义和事件之外的所有代码以查看问题所在,但由于我保留了事件定义,我认为这就是失败的原因。

  4. 然后,在放入更多调试语句并意识到它仅在通过事件调用它时才失败后,我重新编写了事件处理程序并取出了所有 this (this) 引用,但仍然没有运气。

javascript reactjs events material-ui
1个回答
0
投票

我最终解决了这个纯粹是偶然的事情,这也是最可笑的事情。代码没有任何问题。我使用Mac在docker中进行开发。经过至少 2 到 3 天的努力,我碰巧注意到类似的对话框在另一个不相关的应用程序中不起作用。 Mac 很少出现错误或问题,而且它们不会重新启动,所以我从来没有想到我可能遇到了关闭 Mac 界面上文件对话框的错误。如果我没有偶然注意到这一点,我可能一个月都没有解决这个问题。所以,这是一个事件问题,只是不在我的应用程序中。对话框事件中的一些错误已完全全局关闭 Mac 界面上的文件对话框。简单的重新启动并重新加载 docker 镜像就解决了这个问题。

谢谢。

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