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

如何在useRuns请求完成runs更新时同步更新currentRuns?

问题:当useRuns请求完成且runs更新时,如何同步更新currentRuns?

问题详情

  • currentRuns初始被设置为useRuns中runs的初始空数组
  • useRuns请求完成后,currentRuns未自动更新
  • 因currentRuns为空,runTable无内容显示
  • 期望useRuns的runs更新时,currentRuns的初始状态也随之同步更新

相关代码

Runs.ts

function useRuns(count: number) {

    const [runs, setRuns] = useState<IRun[]>([])

    useEffect(() => {
        const getRuns = async () => {
            try {
                const runs = await request<IRun[]>(/* 指定count的请求参数 */)
                setRuns(runs)
            } catch (error) {
                /* 错误日志处理 */
            }
        }
        getRuns()
    }, [count])

    const runsSummary = useMemo(() => { 
       /* 计算run汇总数据 */ 
    }, [runs])

    const runTuple: [IRun[], IRunsSummary] = [runs, runsSummary]
    return runTuple
}

LogViewer.tsx

function LogViewer() {
    const [runs, runsSummary] = useRuns(runCount);
    const [currentRuns, setCurrentRuns] = useState<IRun[]>(runs)

    const addFilter = (columnName: keyof IRun) => (value: string | string[]) => {
        const filteredRuns = runs.filter(run => {
            /* 过滤逻辑 */
        })
        setCurrentRuns(filteredRuns)
    }

    return (
        <div>
            {/* 使用addFilter的其他组件 */}
            <RunTable runs={currentRuns} />
            {/* 其他内容 */}
        </div>
    )
}

解决方法

方法1:监听runs变化重置currentRuns

在LogViewer组件中添加useEffect,监听runs的更新,当runs从请求返回新数据时自动重置currentRuns:

function LogViewer() {
    const [runs, runsSummary] = useRuns(runCount);
    const [currentRuns, setCurrentRuns] = useState<IRun[]>(runs)

    // 新增:监听runs变化,同步更新currentRuns
    useEffect(() => {
        setCurrentRuns(runs);
    }, [runs]);

    const addFilter = (columnName: keyof IRun) => (value: string | string[]) => {
        const filteredRuns = runs.filter(run => {
            /* 过滤逻辑 */
        })
        setCurrentRuns(filteredRuns)
    }

    return (
        <div>
            {/* 使用addFilter的其他组件 */}
            <RunTable runs={currentRuns} />
            {/* 其他内容 */}
        </div>
    )
}

原理:useState的初始值仅在组件首次渲染时生效,后续runs更新不会自动同步到currentRuns。通过useEffect监听runs依赖,每次runs变化时调用setCurrentRuns,即可实现同步。

方法2:移除currentRuns状态,用useMemo计算过滤结果

如果过滤逻辑仅依赖runs和过滤条件,可以把过滤条件存为状态,用useMemo实时计算currentRuns,避免维护额外状态:

function LogViewer() {
    const [runs, runsSummary] = useRuns(runCount);
    // 存储过滤条件,示例:key为列名,value为过滤值
    const [filters, setFilters] = useState<Record<keyof IRun, string | string[]>>({});

    // 用useMemo计算过滤后的结果
    const currentRuns = useMemo(() => {
        return runs.filter(run => {
            // 根据filters中的条件进行过滤
            return Object.entries(filters).every(([key, value]) => {
                const runValue = run[key as keyof IRun];
                if (Array.isArray(value)) {
                    return value.includes(runValue as string);
                }
                return runValue === value;
            });
        });
    }, [runs, filters]);

    const addFilter = (columnName: keyof IRun) => (value: string | string[]) => {
        setFilters(prev => ({
            ...prev,
            [columnName]: value
        }));
    }

    return (
        <div>
            {/* 使用addFilter的其他组件 */}
            <RunTable runs={currentRuns} />
            {/* 其他内容 */}
        </div>
    )
}

这种方式更符合React状态管理逻辑,避免了状态不同步问题,同时减少了手动调用setCurrentRuns的代码。

方法3:将过滤逻辑移至RunTable组件

如果过滤逻辑仅服务于RunTable,可以直接把runs和过滤条件传入RunTable,在组件内部完成过滤:

// 修改LogViewer.tsx
function LogViewer() {
    const [runs, runsSummary] = useRuns(runCount);
    const [filters, setFilters] = useState<Record<keyof IRun, string | string[]>>({});

    const addFilter = (columnName: keyof IRun) => (value: string | string[]) => {
        setFilters(prev => ({
            ...prev,
            [columnName]: value
        }));
    }

    return (
        <div>
            {/* 使用addFilter的其他组件 */}
            <RunTable runs={runs} filters={filters} />
            {/* 其他内容 */}
        </div>
    )
}

// RunTable.tsx
function RunTable({ runs, filters }: { runs: IRun[], filters: Record<keyof IRun, string | string[]> }) {
    const filteredRuns = useMemo(() => {
        return runs.filter(run => {
            // 过滤逻辑
            return Object.entries(filters).every(([key, value]) => {
                const runValue = run[key as keyof IRun];
                if (Array.isArray(value)) {
                    return value.includes(runValue as string);
                }
                return runValue === value;
            });
        });
    }, [runs, filters]);

    return (
        {/* 渲染表格内容,使用filteredRuns */}
    )
}

这种方式让组件职责更清晰,LogViewer专注于数据获取和过滤条件管理,RunTable专注于表格渲染和数据过滤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 07:33:22