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

React组件props变化时更新列表触发无限重渲染问题求解

问题原因分析

  • 无限重渲染的根因:你把状态更新逻辑setExpenses直接写在了组件的渲染主流程中,每次组件渲染只要满足判断条件就会触发状态更新,状态更新又会触发组件重新渲染,形成死循环。
  • 直接修改props不生效:React 中 props 是只读属性,你在子组件内执行props.newExpense = null的操作不会实际修改父组件传递下来的属性值,所以判断条件会一直成立。

解决方法

步骤1:用useEffect监听props.newExpense的变化

把新增 expense 的逻辑放到 useEffect 中,只有当props.newExpense发生变化且符合新增条件时才触发状态更新,避免每次渲染都执行判断逻辑。

步骤2:通过父组件回调清空newExpense

父组件传递newExpense的同时,需要额外传递一个清空newExpense的回调函数,子组件完成新增逻辑后调用该回调,通知父组件重置newExpense的值。

修改后的代码如下:

import { useState, useEffect } from 'react';

export default function Expenses(props) {
  const [expenses, setExpenses] = useState(INITIAL_EXPENSES);
  const [filteredYear, setFilteredYear] = useState('2020');

  const filterExpenses = (date) => {
    setFilteredYear(date);
  }

  // 仅当props.newExpense变化时执行新增逻辑
  useEffect(() => {
    if (props.newExpense?.hasOwnProperty('expenseTitle')) {
      setExpenses((prev) => {
        return [...prev, props.newExpense];
      })
      // 调用父组件传入的清空回调,重置父组件中的newExpense
      props.clearNewExpense?.();
    }
  }, [props.newExpense, props.clearNewExpense])

  const filteredExpenses = expenses.filter(exp => exp.expenseDate.getFullYear().toString() === filteredYear);

  return (
    <Card className="expenses">
      <ExpensesFilter year={filteredYear} onExpensesFilter={filterExpenses}/>
      <ExpenseChart expenses={filteredExpenses}/>
      <ExpensesList items={filteredExpenses}/>
    </Card>
  )
}

父组件侧需要同步修改两个点:

  1. 传递clearNewExpense回调函数给Expenses组件,函数逻辑为把父组件中存储的newExpense重置为null/空值
  2. 确保每次新增expense时传递给Expenses组件的newExpense是新的引用值,避免useEffect无法监听到变化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 03:15:03