创建React组件时遇React.useState顶层调用错误求助
解决React抽离GhibliModal组件后出现的“React.useState cannot be called at the top level”错误
错误原因
你的代码存在两个核心问题:
useState是React函数组件专属的钩子,不能在类组件中使用,也不能放在组件定义外部的顶级作用域里。- 你把所有
useState声明都写在了GhibliModal类组件外面,违反了React钩子的使用规则——钩子必须在函数组件的渲染流程内调用。
修复方案
方案1:改为函数组件(推荐)
函数组件与钩子的适配性更好,重构后的代码如下:
import React, { useState } from 'react'; // 请确保导入Container、Button、各模态框组件及图片资源 const GhibliModal = () => { const [showTotModal, setTotShowModal] = useState(false); const openTotModal = () => setTotShowModal(prev => !prev); const [showCasModal, setCasShowModal] = useState(false); const openCasModal = () => setCasShowModal(prev => !prev); const [showGraModal, setGraShowModal] = useState(false); const openGraModal = () => setGraShowModal(prev => !prev); const [showKikModal, setKikShowModal] = useState(false); const openKikModal = () => setKikShowModal(prev => !prev); const [showSpiModal, setSpiShowModal] = useState(false); const openSpiModal = () => setSpiShowModal(prev => !prev); const [showHowModal, setHowShowModal] = useState(false); const openHowModal = () => setHowShowModal(prev => !prev); return ( <Container> <Button onClick={openTotModal}> <img src={tot} alt="tot" height='300' /> </Button> <Button onClick={openCasModal}> <img src={cas} alt="cas" height='300' /> </Button> <Button onClick={openGraModal}> <img src={gra} alt="gra" height='300' /> </Button> <Button onClick={openKikModal}> <img src={kik} alt="kik" height='300' /> </Button> <Button onClick={openSpiModal}> <img src={spi} alt="spi" height='300' /> </Button> <Button onClick={openHowModal}> <img src={how} alt="how" height='300' /> </Button> <TotModal showModal={showTotModal} setShowModal={setTotShowModal}/> <CasModal showModal={showCasModal} setShowModal={setCasShowModal}/> <GraModal showModal={showGraModal} setShowModal={setGraShowModal}/> <KikModal showModal={showKikModal} setShowModal={setKikShowModal}/> <SpiModal showModal={showSpiModal} setShowModal={setSpiShowModal}/> <HowModal showModal={showHowModal} setShowModal={setHowShowModal}/> </Container> ); }; export default GhibliModal;
方案2:保留类组件,使用类组件状态管理
如果要维持类组件结构,需将状态移至类内部,用this.state和this.setState管理:
import React, { Component } from 'react'; // 请确保导入Container、Button、各模态框组件及图片资源 class GhibliModal extends Component { constructor(props) { super(props); this.state = { showTotModal: false, showCasModal: false, showGraModal: false, showKikModal: false, showSpiModal: false, showHowModal: false }; } openTotModal = () => { this.setState(prev => ({ showTotModal: !prev.showTotModal })); }; openCasModal = () => { this.setState(prev => ({ showCasModal: !prev.showCasModal })); }; openGraModal = () => { this.setState(prev => ({ showGraModal: !prev.showGraModal })); }; openKikModal = () => { this.setState(prev => ({ showKikModal: !prev.showKikModal })); }; openSpiModal = () => { this.setState(prev => ({ showSpiModal: !prev.showSpiModal })); }; openHowModal = () => { this.setState(prev => ({ showHowModal: !prev.showHowModal })); }; render() { return ( <Container> <Button onClick={this.openTotModal}> <img src={tot} alt="tot" height='300' /> </Button> <Button onClick={this.openCasModal}> <img src={cas} alt="cas" height='300' /> </Button> <Button onClick={this.openGraModal}> <img src={gra} alt="gra" height='300' /> </Button> <Button onClick={this.openKikModal}> <img src={kik} alt="kik" height='300' /> </Button> <Button onClick={this.openSpiModal}> <img src={spi} alt="spi" height='300' /> </Button> <Button onClick={this.openHowModal}> <img src={how} alt="how" height='300' /> </Button> <TotModal showModal={this.state.showTotModal} setShowModal={(value) => this.setState({ showTotModal: value })}/> <CasModal showModal={this.state.showCasModal} setShowModal={(value) => this.setState({ showCasModal: value })}/> <GraModal showModal={this.state.showGraModal} setShowModal={(value) => this.setState({ showGraModal: value })}/> <KikModal showModal={this.state.showKikModal} setShowModal={(value) => this.setState({ showKikModal: value })}/> <SpiModal showModal={this.state.showSpiModal} setShowModal={(value) => this.setState({ showSpiModal: value })}/> <HowModal showModal={this.state.showHowModal} setShowModal={(value) => this.setState({ showHowModal: value })}/> </Container> ); } } export default GhibliModal;
额外优化建议
可以用一个对象统一管理所有模态框的显示状态,减少重复代码:
// 函数组件优化写法 const GhibliModal = () => { const [modalStates, setModalStates] = useState({ tot: false, cas: false, gra: false, kik: false, spi: false, how: false }); const toggleModal = (modalKey) => { setModalStates(prev => ({ ...prev, [modalKey]: !prev[modalKey] })); }; return ( <Container> <Button onClick={() => toggleModal('tot')}> <img src={tot} alt="tot" height='300' /> </Button> <Button onClick={() => toggleModal('cas')}> <img src={cas} alt="cas" height='300' /> </Button> <Button onClick={() => toggleModal('gra')}> <img src={gra} alt="gra" height='300' /> </Button> <Button onClick={() => toggleModal('kik')}> <img src={kik} alt="kik" height='300' /> </Button> <Button onClick={() => toggleModal('spi')}> <img src={spi} alt="spi" height='300' /> </Button> <Button onClick={() => toggleModal('how')}> <img src={how} alt="how" height='300' /> </Button> <TotModal showModal={modalStates.tot} setShowModal={(value) => setModalStates(prev => ({...prev, tot: value}))}/> <CasModal showModal={modalStates.cas} setShowModal={(value) => setModalStates(prev => ({...prev, cas: value}))}/> {/* 其他模态框同理 */} </Container> ); };
内容的提问来源于stack exchange,提问作者Eric Varghese
相关产品推荐
相关产品推荐

