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;
问题原因分析
重复渲染SplashWindow实例:Main组件中连续渲染了两个完全独立的SplashWindow组件,导致页面出现两个重叠的搜索界面。用户点击输入框时,可能被上层的搜索界面遮挡,或者输入事件被两个组件的状态逻辑干扰,无法正确触发
onChange更新输入框的searchTerm状态。DOM操作逻辑缺陷:SplashWindow中使用
document.querySelector('.splash-window')添加CSS类,该方法仅会选中页面中第一个匹配的元素,第二个SplashWindow实例无法获得fade-in样式,可能因fade-out样式导致元素被隐藏或无法接收交互事件。组件职责重叠: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

