Skip to content

Conversation

@debasish5452v
Copy link

@debasish5452v debasish5452v commented Jan 1, 2026

Description

Fixes #4787

Added defensive null checks to prevent runtime errors when browser storage contains null values.

Changes

  • Created utils/storage.ts with safe storage access utilities
  • Added initializeStorage() function to clean up null values on app load
  • Updated NavBar to use safe setStorageItem() function
  • Prevents "Cannot read properties of null (reading 'length')" error

Testing

  • Tested locally by running dev server
  • Verified no console errors on page load/refresh
  • Storage cleanup runs automatically when app initializes

Summary by CodeRabbit

  • Bug Fixes

    • Improved storage reliability and error handling to reduce runtime errors and crashes.
    • Description truncation is now evaluated once on mount to stabilize UI rendering.
  • Chores

    • Automatic storage cleanup runs on app startup to remove invalid entries.
    • Language preference saving now uses a safer storage mechanism for consistent behavior.

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

- Created utils/storage.ts with safe storage access utilities
- Added initializeStorage() to clean up null values on app load
- Updated NavBar to use safe setStorageItem() function
- Prevents 'Cannot read properties of null (reading length)' error

Fixes asyncapi#4787
@netlify
Copy link

netlify bot commented Jan 1, 2026

Deploy Preview for asyncapi-website ready!

Built without sensitive environment variables

Name Link
🔨 Latest commit 3985c33
🔍 Latest deploy log https://app.netlify.com/projects/asyncapi-website/deploys/695668c231ea6800080124d5
😎 Deploy Preview https://deploy-preview-4830--asyncapi-website.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 1, 2026

📝 Walkthrough

Walkthrough

Adds a browser-safe storage utility (getStorageItem, setStorageItem, initializeStorage), calls initializeStorage once on app mount, replaces a direct localStorage write in NavBar.changeLanguage with setStorageItem, and narrows a ToolsCard useEffect dependency to run only on initial mount.

Changes

Cohort / File(s) Summary
Storage utility module
utils/storage.ts
New module exporting getStorageItem(key, defaultValue), setStorageItem(key, value), and initializeStorage(). All guard against non-browser environments, wrap localStorage access in try/catch, and initializeStorage removes keys with null values.
App initialization
pages/_app.tsx
Adds useEffect to call initializeStorage() on mount; imports useEffect and initializeStorage(). No exported API changes.
NavBar component
components/navigation/NavBar.tsx
Replaces direct localStorage write in changeLanguage (when langPicker is true) with setStorageItem and adds the import.
ToolsCard UI effect
components/tools/ToolsCard.tsx
Changes useEffect dependency from [descriptionRef.current] to [] so truncation check runs only on initial mount; no other behavior changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser
  participant MyApp
  participant NavBar
  participant StorageUtil as StorageUtil
  participant LocalStorage as localStorage

  rect rgb(240,248,255)
    Note over Browser,MyApp: App startup
    Browser->>MyApp: load / mount
    MyApp->>StorageUtil: initializeStorage()
    StorageUtil->>LocalStorage: get keys & getItem(key)
    alt value === null
      StorageUtil->>LocalStorage: removeItem(key)
    end
  end

  rect rgb(245,255,240)
    Note over Browser,NavBar: User selects language
    Browser->>NavBar: select language
    NavBar->>StorageUtil: setStorageItem('lang', value)
    StorageUtil->>LocalStorage: setItem('lang', value)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through keys both old and new,
Nudged out the nulls and tidied the view,
Wrapped calls in care with gentle paws,
Now startup's calm and free of flaws,
A tiny hop — a safer hue.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive The ToolsCard.tsx dependency array change is unrelated to storage null checks and appears outside the scope of issue #4787, though it may be a minor fix that doesn't significantly impact the PR's primary objective. Clarify whether the ToolsCard.tsx useEffect dependency change is intentional or should be addressed separately as it is unrelated to storage cleanup operations.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding defensive null checks for storage cleanup operations, which is the primary objective across all modified files.
Linked Issues check ✅ Passed The pull request fully addresses issue #4787 requirements: defensive null checks prevent TypeError on null storage values, initializeStorage handles cleanup safely, and setStorageItem provides safe storage access.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7c759d and 3985c33.

📒 Files selected for processing (1)
  • components/tools/ToolsCard.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/tools/ToolsCard.tsx
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
  • GitHub Check: Test NodeJS PR - windows-latest

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.

@asyncapi-bot
Copy link
Contributor

asyncapi-bot commented Jan 1, 2026

⚡️ Lighthouse report for the changes in this PR:

Category Score
🔴 Performance 43
🟢 Accessibility 98
🟢 Best practices 92
🟢 SEO 100
🔴 PWA 33

Lighthouse ran on https://deploy-preview-4830--asyncapi-website.netlify.app/

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2747eba and 0df2c01.

📒 Files selected for processing (3)
  • components/navigation/NavBar.tsx
  • pages/_app.tsx
  • utils/storage.ts
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-29T14:21:43.887Z
Learnt from: sammy200-ui
Repo: asyncapi/website PR: 4804
File: components/navigation/Filter.tsx:32-41
Timestamp: 2025-12-29T14:21:43.887Z
Learning: In the Filter component (components/navigation/Filter.tsx), the useEffect hooks are intentionally designed to react only to route/URL changes, not to prop changes (data, checks, onFilter). The omitted dependencies are by design.

Applied to files:

  • pages/_app.tsx
📚 Learning: 2024-11-11T21:30:32.478Z
Learnt from: amanbhoria
Repo: asyncapi/website PR: 3373
File: components/AlgoliaSearch.tsx:313-313
Timestamp: 2024-11-11T21:30:32.478Z
Learning: In the `SearchButton` component within `components/AlgoliaSearch.tsx`, if the component re-renders on every button click and the `useEffect` runs accordingly, adding dependencies to the dependency array might not be necessary.

Applied to files:

  • pages/_app.tsx
  • components/navigation/NavBar.tsx
📚 Learning: 2025-12-29T14:21:28.216Z
Learnt from: sammy200-ui
Repo: asyncapi/website PR: 4804
File: components/navigation/Filter.tsx:32-41
Timestamp: 2025-12-29T14:21:28.216Z
Learning: In the asyncapi/website repository, when you intentionally omit dependencies in React hooks (e.g., useEffect, useMemo), add an eslint-disable comment with an explanatory note above the line to justify the design choice. For example: // eslint-disable-next-line react-hooks/exhaustive-deps: intentionally omitting dependencies to avoid unnecessary re-runs. This helps reviewers understand the rationale and keeps lint guidance informative.

Applied to files:

  • pages/_app.tsx
  • components/navigation/NavBar.tsx
🧬 Code graph analysis (2)
pages/_app.tsx (1)
utils/storage.ts (1)
  • initializeStorage (40-59)
components/navigation/NavBar.tsx (1)
utils/storage.ts (1)
  • setStorageItem (26-34)
🪛 GitHub Actions: PR testing - if Node project
pages/_app.tsx

[error] 26-26: Expected blank line before this statement. padding-line-between-statements

⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
  • GitHub Check: Lighthouse CI
🔇 Additional comments (4)
utils/storage.ts (3)

7-19: LGTM!

The function correctly handles browser vs. SSR environments, null values, and errors. The use of nullish coalescing (??) is appropriate for returning the default value when getItem returns null.


26-34: LGTM!

The function provides a clean wrapper around localStorage.setItem with appropriate error handling and browser environment checks.


40-59: This cleanup is defensive but may be unnecessary under normal localStorage behavior.

The function removes keys where getItem(key) returns null. However, under standard localStorage behavior, if a key exists in Object.keys(localStorage), getItem(key) should always return a string value—null is only returned for keys that don't exist. The condition on line 52 should theoretically never be true.

The code comment mentions preventing errors when "third-party code tries to access .length on storage values," which suggests this is addressing external/environmental edge cases (possibly corrupted storage or browser extensions). However, without concrete evidence of this issue or a reference to issue #4787, this appears to be defensive programming that may not actually prevent the reported error.

If third-party code is the source, consider whether the real fix should be:

  • Validating/sanitizing all storage values before use (already done in getStorageItem with ?? defaultValue)
  • Preventing direct access to raw localStorage outside the utility functions
  • Providing more specific guards where .length is accessed
components/navigation/NavBar.tsx (1)

8-8: LGTM! The migration to the safe storage wrapper is comprehensive.

The replacement of direct localStorage.setItem with the setStorageItem wrapper is correct. The wrapper properly handles SSR safety with typeof window checks and includes error handling with logging.

A codebase audit confirms no remaining direct localStorage usage exists outside the wrapper—the migration is complete and consistent across the codebase.

@codecov
Copy link

codecov bot commented Jan 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (2747eba) to head (3985c33).

Additional details and impacted files
@@            Coverage Diff            @@
##            master     #4830   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           22        22           
  Lines          798       798           
  Branches       146       146           
=========================================
  Hits           798       798           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 97c725e and d7c759d.

📒 Files selected for processing (1)
  • components/tools/ToolsCard.tsx
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-29T14:21:43.887Z
Learnt from: sammy200-ui
Repo: asyncapi/website PR: 4804
File: components/navigation/Filter.tsx:32-41
Timestamp: 2025-12-29T14:21:43.887Z
Learning: In the Filter component (components/navigation/Filter.tsx), the useEffect hooks are intentionally designed to react only to route/URL changes, not to prop changes (data, checks, onFilter). The omitted dependencies are by design.

Applied to files:

  • components/tools/ToolsCard.tsx
📚 Learning: 2024-11-11T21:30:32.478Z
Learnt from: amanbhoria
Repo: asyncapi/website PR: 3373
File: components/AlgoliaSearch.tsx:313-313
Timestamp: 2024-11-11T21:30:32.478Z
Learning: In the `SearchButton` component within `components/AlgoliaSearch.tsx`, if the component re-renders on every button click and the `useEffect` runs accordingly, adding dependencies to the dependency array might not be necessary.

Applied to files:

  • components/tools/ToolsCard.tsx
📚 Learning: 2025-12-29T14:21:28.216Z
Learnt from: sammy200-ui
Repo: asyncapi/website PR: 4804
File: components/navigation/Filter.tsx:32-41
Timestamp: 2025-12-29T14:21:28.216Z
Learning: In the asyncapi/website repository, when you intentionally omit dependencies in React hooks (e.g., useEffect, useMemo), add an eslint-disable comment with an explanatory note above the line to justify the design choice. For example: // eslint-disable-next-line react-hooks/exhaustive-deps: intentionally omitting dependencies to avoid unnecessary re-runs. This helps reviewers understand the rationale and keeps lint guidance informative.

Applied to files:

  • components/tools/ToolsCard.tsx
🪛 GitHub Actions: PR testing - if Node project
components/tools/ToolsCard.tsx

[error] 94-94: Prettier formatting issue detected. Replace the multi-line expression with a single-line form as required by prettier/prettier.

⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Redirect rules - asyncapi-website
  • GitHub Check: Header rules - asyncapi-website
  • GitHub Check: Pages changed - asyncapi-website
🔇 Additional comments (1)
components/tools/ToolsCard.tsx (1)

31-35: LGTM! Correct fix for the dependency array.

The empty dependency array is appropriate here. The truncation check measures DOM layout once after initial mount, and descriptionRef.current is mutable (doesn't trigger re-runs anyway). This resolves potential eslint warnings.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Runtime error when cleaning up storage

2 participants