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

创建React组件时遇React.useState顶层调用错误求助

解决React抽离GhibliModal组件后出现的“React.useState cannot be called at the top level”错误

错误原因

你的代码存在两个核心问题:

  1. useState是React函数组件专属的钩子,不能在类组件中使用,也不能放在组件定义外部的顶级作用域里。
  2. 你把所有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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 07:54:19