Skip to content

Conversation

@ngoiyaeric
Copy link
Collaborator

@ngoiyaeric ngoiyaeric commented Jan 4, 2026

User description

This PR fixes the minified React error #310 by:

  1. Removing duplicate 'use client' directives in calendar-notepad.tsx.
  2. Adding proper cleanup logic and isMounted checks to useEffect hooks in CalendarNotepad.
  3. Stabilizing dependency arrays and preventing infinite re-render loops in MapboxMap, MapQueryHandler, and GeoJsonLayer.
  4. Ensuring that state updates in map-related components only occur when data has actually changed.

These changes prevent hook misuse and unstable render cycles that were causing the application to crash in production builds.


PR Type

Bug fix


Description

  • Remove duplicate 'use client' directive in calendar-notepad.tsx

  • Add isMounted checks and cleanup logic to useEffect hooks

  • Stabilize dependency arrays to prevent infinite re-render loops

  • Optimize state updates to only occur when data actually changes

  • Add error handling and try-catch blocks in map components


Diagram Walkthrough

flowchart LR
  A["Duplicate directives<br/>and unstable hooks"] -->|Remove duplicates| B["Clean directives"]
  A -->|Add isMounted checks| C["Prevent state updates<br/>after unmount"]
  A -->|Stabilize dependencies| D["Prevent infinite<br/>re-renders"]
  A -->|Optimize state updates| E["Only update on<br/>actual changes"]
  B --> F["Fixed React error #310"]
  C --> F
  D --> F
  E --> F
Loading

File Walkthrough

Relevant files
Bug fix
calendar-notepad.tsx
Remove duplicate directive and add cleanup logic                 

components/calendar-notepad.tsx

  • Remove duplicate 'use client' directive at top of file
  • Add isMounted flag to prevent state updates after component unmount
  • Wrap getNotes call in try-catch for error handling
  • Add cleanup function to set isMounted to false on unmount
+12/-4   
geojson-layer.tsx
Stabilize map load listeners and add error handling           

components/map/geojson-layer.tsx

  • Replace map.on('load') with map.once('load') to prevent duplicate
    listeners
  • Add map.off('load', onMapLoad) in cleanup function
  • Wrap layer and source removal in try-catch block for error handling
  • Store isStyleLoaded in variable to improve code clarity
+12/-7   
map-query-handler.tsx
Optimize state updates with position comparison                   

components/map/map-query-handler.tsx

  • Add position comparison logic to prevent redundant state updates
  • Check if new position matches previous position before updating
  • Remove console.log and console.warn statements
  • Optimize state updates for both valid and invalid coordinate cases
+23/-19 
mapbox-map.tsx
Optimize map updates and simplify cleanup logic                   

components/map/mapbox-map.tsx

  • Add JSON comparison to prevent updating drawnFeatures when unchanged
  • Add distance check before calling updateMapPosition to avoid redundant
    flyTo
  • Remove commented-out code and TODO comments
  • Simplify cleanup effect to only handle long-press timer
  • Remove large cleanup block from main useEffect and reduce dependency
    array
+17/-59 

Summary by CodeRabbit

  • Bug Fixes

    • Fixed memory leaks in calendar component with proper cleanup on unmount.
    • Improved error handling for note fetching.
    • Optimized map layer loading and cleanup to prevent listener buildup.
    • Reduced redundant state updates in map query handling.
  • Performance

    • Eliminated unnecessary re-renders in measurement labels and map navigation.
    • Improved map style loading efficiency with caching and event optimization.

✏️ Tip: You can customize this high-level summary in your review settings.

@charliecreates charliecreates bot requested a review from CharlieHelps January 4, 2026 09:52
@vercel
Copy link

vercel bot commented Jan 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
qcx Ready Ready Preview, Comment Jan 4, 2026 9:54am

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 4, 2026

Walkthrough

The PR addresses performance and stability across multiple map and calendar components by adding defensive guards, cleanup handlers, and conditional updates to prevent redundant re-renders and ensure proper state management during component lifecycle transitions.

Changes

Cohort / File(s) Summary
Calendar State Management
components/calendar-notepad.tsx
Removed duplicate "use client" directive; added mounted-flag guard in useEffect to prevent state updates after unmount; wrapped fetch in try/catch with error logging
Map Layer Initialization
components/map/geojson-layer.tsx
Optimized load handling by caching isStyleLoaded and using map.once() for deferred loads; enhanced cleanup with try/catch error logging and conditional layer/source removal
Map Query Handling
components/map/map-query-handler.tsx
Introduced guarded state updates to prevent redundant re-renders when coordinates unchanged; replaced hard-clear logic with conditional null-checks on invalid data
Map Rendering & Interaction
components/map/mapbox-map.tsx
Optimized updateMeasurementLabels to only update drawnFeatures when changed; added distance check to avoid redundant flyTo calls; simplified dependency handling; streamlined long-press cleanup logic

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

Review effort 3/5

Poem

🐰 Hops through the code with careful cheer,
Guards and cleanup now crystal clear,
No more renders spinning round,
Performance gains abound!
Maps fly smooth, state stays sound

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically identifies the main change: fixing React error #310 by stabilizing hooks and removing duplicate directives, which matches the core objectives and the actual changes across all modified components.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@charliecreates
Copy link

charliecreates bot commented Jan 4, 2026

  1. Removing duplicate 'use client' directives in calendar-notepad.tsx is a good clean-up and will help avoid ambiguities between Client vs. Server Components in React 18+ and Next.js, ensuring only a single directive per file.

  2. Adding cleanup logic (isMounted checks and cleanup functions) to useEffect in CalendarNotepad is solid—this prevents updates to unmounted components (classic memory leak/crash source) and makes the async patterns much safer.

  3. Stabilizing dependency arrays for useEffect in map-related files (MapboxMap, MapQueryHandler, GeoJsonLayer) is great. Carefully ensuring dependencies are correct and only include relevant references will prevent infinite re-renders and prop-mismatch bugs. Nice job reducing render churn and irony-inducing “Too many re-renders” errors.

  4. State updates in map components now only trigger when actual data changes. This targets performance pain points and erratic reactivity issues, especially with dynamic geo/map data.

Suggested nitpicks:

  • Double-check that any function or object references passed into dependencies are memoized (via useCallback, useMemo, etc) as needed; if any remain as fresh inline constructions, more unintended effects/re-renders are possible.
  • Confirm that new isMounted patterns don’t silence user-facing errors or swallow up needed state changes—explicit error logging during cleanup is still a good practice during async work.
  • It can help to leave a quick comment explaining tricky useEffect dependency arrays (why certain items are/aren’t included) for future code readers.

Overall: These changes directly address the production crash and improve hook hygiene and component stability. The PR is a clear win for reliability—just ensure that functional dependencies are really stable, and perhaps add a quick explanatory note near the more complex effects.

@qodo-code-review
Copy link
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟡
🎫 #310
🔴 Implement a contextual 3D map render experience.
Support volume measurements in the 3D map context.
Improve depth perception / 3D understanding of models.
Provide automated controls related to the 3D map/model experience.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Error object exposed: The catch block logs the raw error object to the client console which can expose internal
implementation details/stack traces to end users.

Referred Code
} catch (error) {
  console.error('Failed to fetch notes:', error);
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Unstructured console logging: The new console.warn logs an arbitrary exception object which is unstructured and may
include sensitive data depending on the underlying error contents.

Referred Code
try {
  if (map.getLayer(pointLayerId)) map.removeLayer(pointLayerId)
  if (map.getLayer(polygonLayerId)) map.removeLayer(polygonLayerId)
  if (map.getLayer(polygonOutlineLayerId)) map.removeLayer(polygonOutlineLayerId)
  if (map.getSource(sourceId)) map.removeSource(sourceId)
} catch (e) {
  console.warn('Error during GeoJsonLayer cleanup:', e);
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Console-only error handling: The new try/catch only logs via console.error without any user-visible fallback or
structured reporting, so failures may be silently ignored in production UX depending on
logging capture.

Referred Code
try {
  const fetchedNotes = await getNotes(selectedDate, chatId ?? null)
  if (isMounted) {
    setNotes(fetchedNotes)
  }
} catch (error) {
  console.error('Failed to fetch notes:', error);
}

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Restore full cleanup logic

Restore the cleanup logic for map event listeners, draw controls, markers, and
geolocation watchers in the component's unmount phase to prevent memory leaks.

components/map/mapbox-map.tsx [559-566]

 useEffect(() => {
   return () => {
     if (longPressTimerRef.current) {
       clearTimeout(longPressTimerRef.current);
       longPressTimerRef.current = null;
     }
+
+    if (map.current) {
+      map.current.off('moveend', captureMapCenter);
+      if (drawRef.current) {
+        try {
+          map.current.off('draw.create', updateMeasurementLabels);
+          map.current.off('draw.delete', updateMeasurementLabels);
+          map.current.off('draw.update', updateMeasurementLabels);
+          map.current.removeControl(drawRef.current);
+        } catch {}
+      }
+      Object.values(polygonLabelsRef.current).forEach(marker => marker.remove());
+      Object.values(lineLabelsRef.current).forEach(marker => marker.remove());
+      map.current.remove();
+      map.current = null;
+    }
+
+    if (geolocationWatchIdRef.current !== null) {
+      navigator.geolocation.clearWatch(geolocationWatchIdRef.current);
+      geolocationWatchIdRef.current = null;
+    }
   };
 }, []);
  • Apply / Chat
Suggestion importance[1-10]: 10

__

Why: The PR mistakenly removed critical cleanup logic for the map, which will cause severe memory leaks and application instability. Restoring this logic is essential for the component to function correctly.

High
Add missing effect dependencies

Add a dependency array [toolOutput, setMapData] to the useEffect hook to prevent
it from running on every render, which can cause performance issues and infinite
loops.

components/map/map-query-handler.tsx [33-85]

 useEffect(() => {
   if (toolOutput && toolOutput.mcp_response && toolOutput.mcp_response.location) {
     const { latitude, longitude, place_name } = toolOutput.mcp_response.location;
     ...
   } else {
     // This case handles when toolOutput or its critical parts are missing.
     ...
   }
-});
+}, [toolOutput, setMapData]);

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 9

__

Why: The useEffect hook is missing a dependency array, causing it to run on every render. This is a significant performance issue and can lead to infinite loops, so adding [toolOutput, setMapData] is a critical fix.

High
High-level
PR is linked to an incorrect ticket

The PR, which addresses React rendering bugs, is incorrectly linked to ticket
#310, a feature request for a "Contextual 3D Map Render". It should be
associated with a relevant bug ticket for proper tracking.

Solution Walkthrough:

Before:

// PR Metadata
PR Description: "This PR fixes the minified React error #310 by..."
- Removes duplicate 'use client'
- Adds isMounted checks
- Stabilizes dependency arrays
- Prevents infinite re-render loops

// Linked Ticket #310
Title: "Contextual 3D Map Render"
Description: "Volume Measurements, Depth Perception, 3D understanding Models..."
Labels: advanced, Backend

After:

// PR Metadata
PR Description: "This PR fixes bug #XXX by..."
- Removes duplicate 'use client'
- Adds isMounted checks
- Stabilizes dependency arrays
- Prevents infinite re-render loops

// Linked Ticket #XXX (New or Corrected)
Title: "Fix React rendering loops and state update issues"
Description: "Application crashes in production due to hook misuse and unstable render cycles..."
Labels: bug, frontend

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a significant mismatch between the PR's bug-fix content and the linked feature-request ticket, which impacts project traceability and context.

Low
  • More

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0d30030 and af320e8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • components/calendar-notepad.tsx
  • components/map/geojson-layer.tsx
  • components/map/map-query-handler.tsx
  • components/map/mapbox-map.tsx
🧰 Additional context used
🧬 Code graph analysis (3)
components/map/map-query-handler.tsx (1)
components/map/map-data-context.tsx (1)
  • MapData (7-17)
components/calendar-notepad.tsx (2)
lib/actions/calendar.ts (1)
  • getNotes (16-57)
lib/auth/use-current-user.ts (1)
  • fetchUser (10-20)
components/map/mapbox-map.tsx (1)
components/map/map-data-context.tsx (1)
  • MapData (7-17)
🔇 Additional comments (6)
components/calendar-notepad.tsx (1)

23-39: LGTM! Well-implemented cleanup pattern for async effects.

The isMounted flag correctly guards against state updates after unmount, and the try/catch provides proper error handling. This pattern effectively addresses React error #310 for this component.

components/map/geojson-layer.tsx (1)

82-100: LGTM! Robust cleanup pattern for map layers.

The implementation correctly handles both the loaded and loading states. Wrapping cleanup in try/catch prevents unmount failures from breaking the application. The map.off('load', onMapLoad) call at Line 90 is defensive—map.once() auto-removes after firing, so this is a safe no-op in most cases, which is fine for ensuring cleanup consistency.

components/map/map-query-handler.tsx (1)

38-52: Good guarded update pattern to prevent infinite loops.

The position comparison effectively prevents redundant flyTo calls when the target hasn't changed. The implementation assumes targetPosition is always in array form [lng, lat], which is consistent with how this component sets it.

components/map/mapbox-map.tsx (3)

164-169: Good guard to prevent infinite re-render loops.

Using JSON.stringify for deep comparison is effective here. For typical usage with a small number of drawn features, the performance impact is negligible. This correctly prevents the state update from triggering unnecessary re-renders that could cause React error #310.


519-531: Effective optimization to prevent redundant flyTo calls.

The distance threshold check (0.0001 ≈ ~11 meters) is reasonable for determining if the map is already at the target position. This prevents animation stuttering and unnecessary map updates.

One consideration: the Euclidean distance calculation treats latitude and longitude uniformly, which introduces minor inaccuracy at high latitudes, but for this "already at position" threshold use case, it's perfectly acceptable.


558-566: Clean and correct timer cleanup.

The simplified cleanup effect properly clears the long-press timer on unmount. The empty dependency array is correct since this only needs to run cleanup on unmount.

Comment on lines +54 to +61
setMapData(prevData => {
if (prevData.targetPosition === null && prevData.mapFeature === null) return prevData;
return {
...prevData,
targetPosition: null,
mapFeature: null
};
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard condition may not match initial state.

Per map-data-context.tsx, targetPosition and mapFeature are typed as ... | null | undefined. The initial state may have these as undefined rather than null. The check on Line 55 only matches null, so if the initial state uses undefined, this guard won't prevent the first redundant update.

🔎 Suggested fix
 setMapData(prevData => {
-  if (prevData.targetPosition === null && prevData.mapFeature === null) return prevData;
+  if (!prevData.targetPosition && !prevData.mapFeature) return prevData;
   return {
     ...prevData,
     targetPosition: null,
     mapFeature: null
   };
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setMapData(prevData => {
if (prevData.targetPosition === null && prevData.mapFeature === null) return prevData;
return {
...prevData,
targetPosition: null,
mapFeature: null
};
});
setMapData(prevData => {
if (!prevData.targetPosition && !prevData.mapFeature) return prevData;
return {
...prevData,
targetPosition: null,
mapFeature: null
};
});
🤖 Prompt for AI Agents
In components/map/map-query-handler.tsx around lines 54 to 61, the guard only
checks for strict null which misses undefined (initial state allows null |
undefined); change the condition to check for both null and undefined (e.g., use
loose equality null check: if (prevData.targetPosition == null &&
prevData.mapFeature == null) return prevData;) so the redundant state update is
avoided for both null and undefined initial values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants