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

React函数组件函数执行复用旧Prop值而非新值的问题解决

问题解决:React子组件重复触发旧数据弹窗

问题场景

使用React函数组件时,父组件通过calculateAPR异步获取数据后传递给子组件CalculateAprField,子组件计算APR值,若结果为NaN则弹窗提示。但触发弹窗后,再次输入新值执行查询时,子组件会先触发旧数据的弹窗,再渲染新数据。

核心原因

  1. 旧数据未及时重置:父组件发起新查询时,没有先清除旧的aprRes数据,子组件仍持有旧值并在渲染时执行校验逻辑。
  2. 副作用写在渲染函数中:子组件的renderCard是渲染函数的一部分,直接在里面执行alert会导致每次组件渲染(包括旧数据的收尾渲染)都触发副作用,造成重复弹窗。

解决方案

1. 父组件发起查询时重置旧数据

在calculateAPR函数开始执行时,先重置aprRes和renderApr状态,确保子组件不会再使用旧数据:

const calculateAPR = async (val) => {
    setIsAprLoading(true);
    // 先重置aprRes和渲染状态,清除旧数据
    setResData(prev => ({...prev, aprRes: null}));
    setRenderApr(false);
    try {
        if (val.addr !== "" && val.date !== null) {
            const totalStaking = await someEP.getSomeData(val.addr);
            // 不要直接修改传入的val,创建新对象避免引用问题
            const newAprRes = {...val, staked: totalStaking};
            setResData((prevState) => ({
                ...prevState,
                aprRes: newAprRes
            }));
            setRenderApr(true);
        }
        else {
            alert(Constants.ADDR_N_DATE_ERR);
        }
    }
    catch (err) {
        console.log(err);
        alert(Constants.ADDR_NO_DATA);
    }
    finally {
        setIsAprLoading(false);
    }  
}

2. 子组件将副作用移至useEffect,避免渲染时触发

把APR计算和错误提示的逻辑从渲染函数中抽离,用useEffect监听props变化,单独处理副作用:

import { useState, useEffect } from 'react';

function CalculateAprField(props) {
    const [validApr, setValidApr] = useState(null);
    const [showError, setShowError] = useState(false);

    // 监听props变化,计算APR并校验
    useEffect(() => {
        // 没有渲染指令或数据为空时,重置状态
        if (!props.onRender || !props.resData) {
            setValidApr(null);
            setShowError(false);
            return;
        }

        const aprInput = setAprInputs(props.resData);
        const { staked } = extractAprInput(aprInput);
        const apr = parseFloat(calculateAPR(staked, accrued, withdrawn, numOfDays).toFixed(5));
        
        if (isNaN(apr)) {
            setShowError(true);
            setValidApr(null);
        } else {
            setShowError(false);
            setValidApr(apr);
        }
    }, [props.resData, props.onRender]);

    // 单独处理错误弹窗的副作用
    useEffect(() => {
        if (showError) {
            alert(Constants.APR_AUTO_ERR);
            setShowError(false); // 弹窗后重置状态,避免重复触发
        }
    }, [showError]);

    const renderCard = () => {
        // 只有存在有效APR且允许渲染时,才显示结果卡片
        if (props.onRender && validApr !== null) {
            return (
                <Paper elevation={4}>
                    {/* 你的结果展示代码 */}
                </Paper>
            );
        }
        return null;
    }

    return (
        <Box>
            {renderCard()}
        </Box>
    )
}

关键优化点

  • 父组件在发起新请求前重置数据,切断旧数据的传递路径。
  • 子组件将副作用(弹窗)从渲染逻辑中分离,通过useEffect监听状态变化触发,避免渲染过程中执行副作用。
  • 使用状态管理有效APR值,确保只有合法数据才会渲染结果卡片。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:55:18