fix: CRM report renders blank due to stale useState initialization#523
fix: CRM report renders blank due to stale useState initialization#523
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ding state The ReportView component had a stale state bug where reportData was initialized via useState(initialReport) on first render when metadata was still loading (reports=[]), causing it to remain undefined even after metadata loaded. Added useEffect to sync state and loading check. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
❌ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a critical bug where the CRM report view renders blank due to stale state initialization. The ReportView component was initializing reportData state with useState(initialReport) during the first render when metadata was still loading asynchronously, permanently capturing undefined. The fix adds a useEffect to synchronize state when metadata loads and a loading guard to show a spinner instead of a false "Report Not Found" error.
Changes:
- Added
useEffectto syncreportDatastate wheninitialReportchanges (metadata loads or route changes) - Added loading state check with spinner UI to prevent false "Report Not Found" during async metadata fetch
- Imported
Loader2icon for loading spinner anduseEffecthook
|
|
||
| // Sync reportData when metadata finishes loading or reportName changes | ||
| useEffect(() => { | ||
| setReportData(initialReport); |
There was a problem hiding this comment.
The useEffect should also reset the editing state when the report changes (either from metadata loading or navigation). Currently, if a user is editing "Report A" and navigates to "Report B", they remain in editing mode showing "Report B" data in the builder. This creates confusion as the edit UI doesn't reset. Add setIsEditing(false); inside this effect to ensure clean state transitions between reports.
| setReportData(initialReport); | |
| setReportData(initialReport); | |
| setIsEditing(false); |
| const { reports, loading } = useMetadata(); | ||
| const initialReport = reports?.find((r: any) => r.name === reportName); | ||
| const [reportData, setReportData] = useState(initialReport); | ||
|
|
||
| // Sync reportData when metadata finishes loading or reportName changes | ||
| useEffect(() => { | ||
| setReportData(initialReport); | ||
| }, [initialReport]); | ||
|
|
||
| if (loading) { | ||
| return ( | ||
| <div className="h-full flex items-center justify-center p-8"> | ||
| <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" /> | ||
| </div> | ||
| ); | ||
| } |
There was a problem hiding this comment.
The loading check occurs after the initialReport has already been computed from the potentially empty reports array. Since reports starts as [] during initial load, initialReport will be undefined even during loading. This means users will briefly see the loading spinner (correct), but the initialReport constant and reportData state will both be undefined until the next render after metadata loads. While the useEffect will fix reportData when metadata arrives, this pattern is inconsistent with how the metadata is used. Consider moving the loading check before computing initialReport to make the control flow clearer, or acknowledge that initialReport is recomputed on every render (which is fine but could be clarified with a comment).
ReportViewinitializesreportDataviauseState(initialReport)during first render, when metadata is still loading asynchronously (reports=[]). This capturesundefinedpermanently — subsequent metadata loads updateinitialReportbut never sync back toreportData, rendering a blank report.Changes
useEffectto propagateinitialReport→reportDatawhen metadata finishes loading or route changesloadingfromuseMetadata()and show spinner instead of false "Report Not Found"Note:
reportDatastate is retained (not replaced with directinitialReportusage) becausehandleSavewrites edited report data back into it.Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.