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

React项目中输入文本框无法输入问题求助

问题:React输入文本框无法输入,无报错信息

使用create-react-app开发大学作业网站时,遇到输入文本框无法键入内容的问题,点击文本框后无任何反应,且控制台无报错信息。输入框的设计逻辑为:用户输入搜索词,匹配NewsLibrary.json中的文章后,将对应数据加载到News、VideoBox和EventsBox组件并在Main中展示。目前这些组件可正常加载,无匹配时会显示“Not available”,但输入框无法输入。

相关代码

SplashWindow组件(含输入框)

import React, { useEffect, useState } from "react";
import { Button, Form, Alert } from 'react-bootstrap';
import NewsLibrary from "./NewsLibrary.json";
import News from "./News";
import VideoBox from "../Aside/VideoBox";
import EventsBox from "./EventsBox";

const SplashWindow = () => {

    const [searchTerm, setSearchTerm] = useState('');
    const [errorMessage, setErrorMessage] = useState('');
    const [showContent, setShowContent] = useState(false);
    const [foundArticle, setFoundArticle] = useState(null);

    useEffect(() =>{
        document.querySelector('.splash-window').classList.add('fade-in');
    }, []);

    const handleSearch = (event) => {
        event.preventDefault();

        if (!searchTerm) {
            setErrorMessage('Please Enter a search term');
            setFoundArticle(false);
            setShowContent(false);
            return;
        }

        const foundArticle = NewsLibrary.find((article) =>
            article.title.toLowerCase().includes(searchTerm.toLowerCase())
        );

        if (foundArticle) {
            setErrorMessage('');
            setShowContent(true);
            setFoundArticle(foundArticle);
        } else {
            setErrorMessage('No Matching Article Found');
            setShowContent(false);
            setFoundArticle(null);
        }
    };

    return (
        <>
        {!showContent && (
            <div className="splash-window fade-out">
                <div className="splash-content">
                 <h1>Welcome To Future Sports!</h1>
                  <p>
                  To begin in the search box below search any sporting event you would to learn more about.
                  Or if your not sure what you want you can always type in /Random to be surprised!
                  </p>
                 <Form onSubmit={handleSearch} className="search-form">
                  <div className="search-group">
                 <Form.Control type="text" placeholder="Enter your Search Query" className="search-input" name="searchTerm" value={searchTerm} onChange={(e) => 
                 setSearchTerm(e.target.value)
                 }/>
                <Button variant="primary" type="submit" className="splashSearchButton">Search</Button>
               </div>
              </Form>
             {errorMessage && <Alert variant="danger">{errorMessage}</Alert>}
             </div>
            </div>
        )}
        {showContent && foundArticle && (
            <>
            <News article={foundArticle} />
            <VideoBox article={foundArticle} />
            <EventsBox article={foundArticle} />
            </>
        )}
        </>
    );
};

export default SplashWindow;

Main组件

import React, { useState, useEffect } from "react";
import ContactUs from "./ContactUs"
import PhotoGallery from "./PhotoGallery";
import News from "./News";
import EventsBox from "./EventsBox";
import SplashWindow from "./SplashWindow"
import NewsLibrary from "./NewsLibrary"

const Main = () => {

    const [foundNewsArticle, setFoundNewsArticle] = useState(null);
    const [foundEventsArticle, setFoundEventsArticle] = useState(null);

    useEffect(() => {
        const fetchData = () => {
            setTimeout(() => {
                setFoundNewsArticle(NewsLibrary);
                setFoundEventsArticle(NewsLibrary);
                }, 1000);
            };
        fetchData();
    }, []);

    const handleSetFoundArticle = (article) => {
        setFoundNewsArticle(article);
        setFoundEventsArticle(article);
    }; 

    return (
        <div className="MainSection">
            <ContactUs />
            <PhotoGallery />
            <>
            <div>
             <h3>News Component</h3>
             <SplashWindow setFoundArticle={handleSetFoundArticle} />
             {foundNewsArticle && <News article={foundNewsArticle} />}
            </div>
            
            <div>
             <h3>Events Component</h3>
             <SplashWindow setFoundArticle={handleSetFoundArticle} />
             {foundEventsArticle && <EventsBox article={foundEventsArticle} />}
            </div>
            </>
        </div>
    );
};

export default Main;

问题原因分析

  1. 重复渲染SplashWindow实例:Main组件中连续渲染了两个完全独立的SplashWindow组件,导致页面出现两个重叠的搜索界面。用户点击输入框时,可能被上层的搜索界面遮挡,或者输入事件被两个组件的状态逻辑干扰,无法正确触发onChange更新输入框的searchTerm状态。

  2. DOM操作逻辑缺陷:SplashWindow中使用document.querySelector('.splash-window')添加CSS类,该方法仅会选中页面中第一个匹配的元素,第二个SplashWindow实例无法获得fade-in样式,可能因fade-out样式导致元素被隐藏或无法接收交互事件。

  3. 组件职责重叠:SplashWindow自身负责渲染News、VideoBox和EventsBox组件,同时Main组件也在渲染这些组件,导致状态管理混乱,进一步干扰输入框的正常交互流程。

解决方案

1. 调整Main组件:只渲染一次SplashWindow,统一控制界面状态

修改Main组件,仅渲染一个SplashWindow实例,通过状态控制搜索界面的显示/隐藏,以及搜索结果的展示:

import React, { useState } from "react";
import ContactUs from "./ContactUs"
import PhotoGallery from "./PhotoGallery";
import News from "./News";
import EventsBox from "./EventsBox";
import SplashWindow from "./SplashWindow"

const Main = () => {
    const [foundArticle, setFoundArticle] = useState(null);
    const [showSplash, setShowSplash] = useState(true);

    const handleSearchComplete = (article) => {
        setFoundArticle(article);
        setShowSplash(false);
    };

    return (
        <div className="MainSection">
            <ContactUs />
            <PhotoGallery />
            {showSplash ? (
                <SplashWindow onSearchComplete={handleSearchComplete} />
            ) : (
                <>
                    <div>
                        <h3>News Component</h3>
                        {foundArticle && <News article={foundArticle} />}
                    </div>
                    <div>
                        <h3>Events Component</h3>
                        {foundArticle && <EventsBox article={foundArticle} />}
                    </div>
                </>
            )}
        </div>
    );
};

export default Main;

2. 重构SplashWindow组件:专注搜索逻辑,移除内部组件渲染

修改SplashWindow,仅负责搜索功能,搜索完成后通知父组件Main,同时使用React ref替代document.querySelector来操作DOM:

import React, { useEffect, useState, useRef } from "react";
import { Button, Form, Alert } from 'react-bootstrap';
import NewsLibrary from "./NewsLibrary.json";

const SplashWindow = ({ onSearchComplete }) => {
    const [searchTerm, setSearchTerm] = useState('');
    const [errorMessage, setErrorMessage] = useState('');
    const splashRef = useRef(null);

    useEffect(() =>{
        if (splashRef.current) {
            splashRef.current.classList.add('fade-in');
        }
    }, []);

    const handleSearch = (event) => {
        event.preventDefault();

        if (!searchTerm) {
            setErrorMessage('Please Enter a search term');
            return;
        }

        // 处理/Random随机搜索逻辑
        if (searchTerm.trim().toLowerCase() === '/random') {
            const randomIndex = Math.floor(Math.random() * NewsLibrary.length);
            const randomArticle = NewsLibrary[randomIndex];
            setErrorMessage('');
            onSearchComplete(randomArticle);
            return;
        }

        const foundArticle = NewsLibrary.find((article) =>
            article.title.toLowerCase().includes(searchTerm.toLowerCase())
        );

        if (foundArticle) {
            setErrorMessage('');
            onSearchComplete(foundArticle);
        } else {
            setErrorMessage('No Matching Article Found');
        }
    };

    return (
        <div ref={splashRef} className="splash-window fade-out">
            <div className="splash-content">
                <h1>Welcome To Future Sports!</h1>
                <p>
                    To begin in the search box below search any sporting event you would to learn more about.
                    Or if your not sure what you want you can always type in /Random to be surprised!
                </p>
                <Form onSubmit={handleSearch} className="search-form">
                    <div className="search-group">
                        <Form.Control 
                            type="text" 
                            placeholder="Enter your Search Query" 
                            className="search-input" 
                            name="searchTerm" 
                            value={searchTerm} 
                            onChange={(e) => setSearchTerm(e.target.value)}
                        />
                        <Button variant="primary" type="submit" className="splashSearchButton">Search</Button>
                    </div>
                </Form>
                {errorMessage && <Alert variant="danger">{errorMessage}</Alert>}
            </div>
        </div>
    );
};

export default SplashWindow;

3. 移除冗余逻辑

删除Main中原有的useEffect模拟数据请求逻辑,因为现在搜索结果由SplashWindow的搜索流程控制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 08:42:03