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

React Calendar Timeline仅在F12或窗口调整后渲染Items问题

react-calendar-timeline 异步加载items后不渲染,仅窗口调整/打开控制台后显示

问题现象

  • groups数组可正常渲染,手动传入items值时组件显示正常
  • 通过后端接口获取的items数据,仅在按下F12打开控制台或调整浏览器窗口后才会渲染到时间线上
  • 已确认后端接口返回数据正常

相关代码

组件代码

import React, { useEffect, useState } from 'react'
import Timeline from 'react-calendar-timeline'
import 'react-calendar-timeline/lib/Timeline.css'
import moment from 'moment'
import { getProd } from '../services/frontendRoutes'

export default function Production() {
    const [groups, setGroups] = useState([]);
    const [items, setItems] = useState([]);

    const fetchData = async () => {
        try {
            const { data } = await getProd();
            setGroups(data.data.groups);
            const item = data.data.items;
            let itemss = item.map(i => {
                i.start_time = moment(i.start_time, 'YYYY-MM-DDTHH:mm:ss');
                i.end_time = moment(i.end_time, 'YYYY-MM-DDTHH:mm:ss');
                return i;
            })
            setItems(itemss);
        } catch (err) {
            console.log(err)
        }
    }

    useEffect(() => {
        fetchData()
    }, [])

    return (
        <div>
            <div>
                Production
                <Timeline
                    groups={groups}
                    items={items}
                    defaultTimeStart={moment().startOf('year').toDate()}
                    defaultTimeEnd={moment().endOf('year').toDate()}
                />
            </div>
        </div>
    )
}

Axios请求代码

import axios from 'axios'
const apiUrl_prod = 'http://localhost:8000/api/prod';
const apiUrl_sub = 'http://localhost:8000/api/sub'
const apiUrl_paint = 'http://localhost:8000/api/paint'
const apiUrl_final = 'http://localhost:8000/api/final'

export function getProd() {
    return axios.get(apiUrl_prod);
}

export function getSub() {
    return axios.get(apiUrl_sub);
}

export function getPaint() {
    return axios.get(apiUrl_paint)
}

export function getFinal() {
    return axios.get(apiUrl_final);
}

截图对比

  • 按下F12前:按下F12前
  • 按下F12后:按下F12后

解决方案

方案1:创建新对象避免引用复用

直接修改后端返回的原对象属性,会导致React浅比较无法检测到items数组变化。修改map逻辑,创建新对象而非修改原对象:

let itemss = item.map(i => ({
  ...i,
  start_time: moment(i.start_time, 'YYYY-MM-DDTHH:mm:ss'),
  end_time: moment(i.end_time, 'YYYY-MM-DDTHH:mm:ss')
}))

方案2:手动触发组件刷新

react-calendar-timeline在异步更新数据后可能不会自动重绘,通过ref调用组件的refresh方法强制刷新:

import React, { useEffect, useState, useRef } from 'react'

export default function Production() {
    const [groups, setGroups] = useState([]);
    const [items, setItems] = useState([]);
    const timelineRef = useRef(null);

    const fetchData = async () => {
        try {
            const { data } = await getProd();
            setGroups(data.data.groups);
            const item = data.data.items;
            let itemss = item.map(i => ({
                ...i,
                start_time: moment(i.start_time, 'YYYY-MM-DDTHH:mm:ss'),
                end_time: moment(i.end_time, 'YYYY-MM-DDTHH:mm:ss')
            }))
            setItems(itemss);
        } catch (err) {
            console.log(err)
        }
    }

    useEffect(() => {
        fetchData()
    }, [])

    useEffect(() => {
        if (timelineRef.current && items.length > 0) {
            timelineRef.current.refresh();
        }
    }, [items])

    return (
        <div>
            <div>
                Production
                <Timeline
                    ref={timelineRef}
                    groups={groups}
                    items={items}
                    defaultTimeStart={moment().startOf('year').toDate()}
                    defaultTimeEnd={moment().endOf('year').toDate()}
                />
            </div>
        </div>
    )
}

方案3:添加加载状态,确保数据就绪后渲染

添加loading状态,等待groups和items都加载完成后再渲染Timeline组件:

export default function Production() {
    const [groups, setGroups] = useState([]);
    const [items, setItems] = useState([]);
    const [loading, setLoading] = useState(true);

    const fetchData = async () => {
        try {
            const { data } = await getProd();
            setGroups(data.data.groups);
            const item = data.data.items;
            let itemss = item.map(i => ({
                ...i,
                start_time: moment(i.start_time, 'YYYY-MM-DDTHH:mm:ss'),
                end_time: moment(i.end_time, 'YYYY-MM-DDTHH:mm:ss')
            }))
            setItems(itemss);
        } catch (err) {
            console.log(err)
        } finally {
            setLoading(false);
        }
    }

    useEffect(() => {
        fetchData()
    }, [])

    if (loading) {
        return <div>加载中...</div>;
    }

    return (
        <div>
            <div>
                Production
                <Timeline
                    groups={groups}
                    items={items}
                    defaultTimeStart={moment().startOf('year').toDate()}
                    defaultTimeEnd={moment().endOf('year').toDate()}
                />
            </div>
        </div>
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:18:35