You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React模态框表单输入无法点击问题排查求助

React模态框表单输入交互异常排查与修复

问题现象

  • 模态框表单仅顶部第一个输入框可点击,其余输入框无法交互
  • 缩小浏览器宽度后,第二个输入框恢复可点击状态
  • 问题出现时间与引入react-toastify同步,已排除后端问题

相关代码

Modal组件

import {useState} from 'react';

const Modal = ({open, close, submitForm}) => {
    const [task, setTask] = useState('');
    const [cat, setCat] = useState('');
    const [deadline, setDeadline] = useState('');

    const handleSub = (e) => {
        e.preventDefault();
        submitForm({'task': task, 'cat': cat, 'ddln': deadline});
        setTask('');
        setCat('');
        setDeadline('');
    }
    
    // 原渲染逻辑:仅当open为false时返回模态框,open为true时无返回值
    if(!open){
        return (
            <div className="myOverlay">
                <div className="myModal">
                    <strong onClick={close}>X</strong><br />
                    <form method="post" onSubmit={handleSub} >
                      <div className="form-group">
                        <label htmlFor="exampleInputEmail1">Task</label>
                        <input type="text" className="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter task" name="task" value={task} onChange={(e) =>setTask(e.target.value)}/>
                      </div><br />
                      <div className="form-group">
                          <select className="form-control" defaultValue={cat} id="inlineFormCustomSelectPref" name="cat" onChange={(e) =>setCat(e.target.value)}>
                            <option>Task category</option>
                            <option value="Tech">Tech</option>
                            <option value="Marketing">Marketing</option>
                            <option value="Financial">Financial</option>
                            <option value="Admin">Admin</option>
                          </select>
                      </div>
                      <br />
                      <div className="form-group">
                        <label htmlFor="exampleInputPassword1">Deadline</label>
                        <input type="date" className="form-control" id="exampleInputPassword1" placeholder="Deadline" name="ddln" value={deadline} onChange={(e) =>setDeadline(e.target.value)}/>
                      </div>
                      <div className="form-check">
                        <input type="checkbox" className="form-check-input" id="exampleCheck1" />
                        <label className="form-check-label" htmlFor="exampleCheck1">Make Task Active</label>
                      </div> <br />
                      <input type="submit" className="btn btn-dark" value="Submit"/>
                    </form>
                </div>
            </div>
        );
    }
}

export default Modal

Root组件

import { Outlet } from 'react-router-dom';
import { useState } from 'react';
import Sidebar from './Sidebar';
import Modal from './Modal';

import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const Root = () => {
  const [ modal, setModal ] = useState(true);
  const [ page, setPage ] = useState('home');

  const addFormHandle = async (formData) => {
          const res = await fetch('http://127.0.0.1:8000/api/tasks/add', {
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
              },
              body: JSON.stringify(formData),
          });

          if (res.ok) {
            toast.success('Task added successfully', {
              position: "top-right",
              autoClose: 5000,
              hideProgressBar: false,
              closeOnClick: true,
              pauseOnHover: true,
              draggable: true,
              progress: undefined,
              theme: "dark",
            });
          }
          else
          {
            toast.error('Task failed to add please check network connection!!!', {
            position: "top-right",
            autoClose: 5000,
            hideProgressBar: false,
            closeOnClick: true,
            pauseOnHover: true,
            draggable: true,
            progress: undefined,
            theme: "dark",
            });
          }
          setModal(true);
  }

  return(
    <div className='row'>
      <div className="col-md-2">
        <Sidebar page={setPage}  />
      </div>
      <div className="col-md-10">
        <main className="main-sec container">
            <Outlet />
        </main>
        <Modal open={modal} close={()=>setModal(true)} submitForm={addFormHandle} />
      </div>
      <div className="myContainer">
          <button className="btn btn-dark fixed-button" onClick={()=>setModal(false)}>Add Task</button>
      </div>
    </div>
  )
}

export default Root;

App组件

import { createBrowserRouter, createRoutesFromElements, Route, Outlet, RouterProvider} from 'react-router-dom';
import { useState } from 'react';
import Sidebar from './Components/Sidebar';
import Cards from './Components/Main/Cards';
import Table from './Components/Main/Table';
import Modal from './Components/Modal';
import Deadlines from './Components/Deadlines';
import Home from './Components/Home';
import Tasks from './Components/Tasks';
import Inoives from './Components/Inoives';
import Root from './Components/Root';
import DataLoada from './DataLoada.js';
import { ToastContainer } from 'react-toastify';

function App() {
  const router = createBrowserRouter(
      createRoutesFromElements(
          <Route path="/" element={<Root />}>
              <Route index element={<Home />} />
              <Route path="/deadlines" element={<Deadlines />} />
              <Route path="/tasks" element={<Tasks />} loader={DataLoada} />
              <Route path="/invoices" element={<Inoives />} />
          </Route>
      )
  );

  return (
    <>
      <RouterProvider router={router} />
      <ToastContainer />
    </>
  );
}

export default App;

修复方案

1. 修正Modal组件的渲染逻辑

原代码中当open为true时,Modal组件没有返回任何内容,会导致React渲染异常,影响DOM结构层级。调整逻辑,确保组件始终返回有效JSX:

const Modal = ({open, close, submitForm}) => {
    // ...state和handleSub保持不变

    // 当open为true时,不显示模态框,返回null
    if(open){
        return null;
    }

    // 否则渲染完整模态框
    return (
        <div className="myOverlay">
            {/* 原模态框内容 */}
        </div>
    );
}

2. 调整模态框的CSS层级,避免被覆盖

react-toastify的默认z-index为9999,会覆盖模态框元素,导致输入框无法点击。给模态框添加足够高的z-index:

/* 模态框遮罩层 */
.myOverlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 10000; /* 高于ToastContainer的默认层级 */
    display: flex;
    justify-content: center;
    align-items: center;
}

/* 模态框主体 */
.myModal {
    background-color: #fff;
    padding: 2rem;
    border-radius: 8px;
    z-index: 10001; /* 高于遮罩层 */
    position: relative;
    width: 90%;
    max-width: 500px;
}

3. 可选:调整ToastContainer的层级

如果不想修改模态框层级,也可以降低ToastContainer的z-index,确保模态框在上方:

// App.js中修改ToastContainer
<ToastContainer zIndex={9999} />

(注:若模态框z-index设为10000,则Toast的9999会在下方)

问题根源分析

  • 模态框渲染逻辑错误导致组件状态异常,影响DOM渲染的稳定性
  • react-toastify的ToastContainer默认z-index过高,覆盖了模态框的输入元素,导致无法交互
  • 浏览器宽度变化时,元素布局重排可能临时改变层级关系,出现部分输入框可点击的现象

内容的提问来源于stack exchange,提问作者Lwazi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:31:08