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

React中soupRequest被重置为初始值的原因及修复方案

问题修复方案

核心问题分析

  1. 初始状态设计缺陷:soupRequest初始值为null,导致第一次useEffect执行时需额外赋值,触发重复渲染。
  2. Cleanup逻辑错误:useEffect的cleanup函数中设置setisLooading(true),每次soupRequest更新时强制切换到Loading状态,卸载ControlPanel导致临时输入状态丢失。
  3. 子组件状态不同步:ControlPanel的本地状态tmpRequest仅在挂载时初始化,父组件soupRequest更新时无法同步,导致输入框显示异常。
  4. 错误捕获遗漏参数:try/catch中未接收error参数,导致控制台报错中断流程。

分步修复代码

1. 修复LetterSoup.jsx

import { useEffect, useState } from 'react';
import ControlPanel from '../components/ControlPanel';
import Grid from '../components/Grid';
import Words from '../components/Words';

function LetterSoup() {
    // 直接设置默认参数值,避免初始null导致的额外逻辑
    const [soupRequest, setsoupRequest] = useState({ gridNum: 15, wordNum: 10, charNum: 4 });
    const [letterSoup, setletterSoup] = useState(null);
    const [isLoading, setisLoading] = useState(true);

    const childToParent = (childdata) => {
        setsoupRequest(childdata);
    };

    const contents = isLoading ? (
        <p>Loading...</p>
    ) : (
        <div className="lettersoup_container">
            <h1 id="tabelLabel">Sopa de letras (PT)</h1>
            <div className="controlpanel_container">
                <ControlPanel soupRequest={soupRequest} childToParent={childToParent} />
            </div>
            <div>{letterSoup?.wordsNum} palavras</div>
            {/* <div className="grid_container">
                <Grid board={letterSoup.board} />
            </div>
            <div className="words_container">
                <Words words={letterSoup.words} />
            </div> */}
        </div>
    );

    useEffect(() => {
        let ignore = false;
        async function fetchData() {
            setisLoading(true); // 发起请求时才设置Loading
            const aux = `/lettersoup/${soupRequest.gridNum}/${soupRequest.wordNum}/${soupRequest.charNum}`;

            try {
                const response = await fetch(aux);
                if (!ignore && response.ok) {
                    const data = await response.json();
                    setletterSoup(data);
                    setisLoading(false);
                } else if (!ignore) {
                    throw new Error("Requisição falhou");
                }
            } catch (error) { // 接收error参数
                if (!ignore) {
                    console.log(error.message);
                    setisLoading(false);
                }
            }
        }

        fetchData();

        return () => {
            ignore = true;
            // 移除cleanup中的setisLoading(true),避免不必要的状态切换
        };
    }, [soupRequest]);

    return (<div>{contents}</div>);
}

export default LetterSoup;

2. 修复ControlPanel.jsx

import { useId, useState, useEffect } from 'react';

function ControlPanel({ soupRequest, childToParent }) {
    const inputId = useId();
    const [tmpRequest, setTmpRequest] = useState(soupRequest);

    // 同步父组件的soupRequest到本地状态
    useEffect(() => {
        setTmpRequest(soupRequest);
    }, [soupRequest]);

    // 使用函数式更新,避免闭包问题
    const handleGridChange = (e) => {
        setTmpRequest(prev => ({
            ...prev,
            gridNum: parseInt(e.target.value)
        }));
    };

    const handleWordChange = (e) => {
        setTmpRequest(prev => ({
            ...prev,
            wordNum: parseInt(e.target.value)
        }));
    };

    const handleCharChange = (e) => {
        setTmpRequest(prev => ({
            ...prev,
            charNum: parseInt(e.target.value)
        }));
    };

    // 阻止表单默认提交行为,避免页面刷新
    const handleSubmit = (e) => {
        e.preventDefault();
        childToParent(tmpRequest);
    };

    return (
        <form className="controlpanel" onSubmit={handleSubmit}>
            <div className="controlpanel_settings">
                <div className="controlapanel_setting">
                    <label htmlFor={inputId}>Tamanho da grelha</label>
                    <input
                        type="number"
                        value={tmpRequest.gridNum}
                        min="10"
                        max="25"
                        step="5"
                        id={inputId}
                        name="gridNum"
                        onChange={handleGridChange}
                        className="controlpanel_setting_input"
                    />
                </div>
                <div className="controlapanel_setting">
                    <label htmlFor={`${inputId}-1`}>Número de palavras</label>
                    <input
                        type="number"
                        value={tmpRequest.wordNum}
                        min="10"
                        max="50"
                        step="1"
                        id={`${inputId}-1`}
                        name="wordNum"
                        onChange={handleWordChange}
                        className="controlpanel_setting_input"
                    />
                </div>
                <div className="controlapanel_setting">
                    <label htmlFor={`${inputId}-2`}>Mínimo de letras</label>
                    <input
                        type="number"
                        value={tmpRequest.charNum}
                        min="3"
                        max="20"
                        step="1"
                        id={`${inputId}-2`}
                        name="charNum"
                        onChange={handleCharChange}
                        className="controlpanel_setting_input"
                    />
                </div>
            </div>
            <div className="controlpanel_button">
                <button type="submit">GO</button>
            </div>
        </form>
    );
}

export default ControlPanel;

关键修改说明

  1. 初始状态赋值:给soupRequest设置默认参数,避免null值导致的重复useEffect触发和额外状态更新。
  2. 调整Loading时机:仅在发起请求时设置isLoading=true,移除cleanup中的状态切换,保证ControlPanel不会被频繁卸载。
  3. 子组件状态同步:通过useEffect监听父组件soupRequest变化,同步更新本地临时状态,确保输入框显示最新值。
  4. 优化输入事件处理:使用函数式更新修改tmpRequest,避免闭包导致的状态更新异常;阻止表单默认提交行为,防止页面刷新。
  5. 修复错误捕获:在catch中接收error参数,确保错误信息能正常打印。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:50:59