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

NextJS13以下:自定义响应式Hook的Hydration Error解决问询

Hey there! Let's work through those two issues you're hitting with your Next.js (pre-13) + Chakra UI layout hook. I've got a couple of solutions to fix the hydration error and initial value mismatch, plus an alternative approach that leverages Chakra's built-in tools to avoid reinventing the wheel.

Fixing the Hydration Error & Initial Value Issue

The root problem here is that Next.js renders your component on the server first, where window doesn't exist—so calling determineDisplayItemsCount() during initial state setup throws an error. Additionally, setting a static initial value (like 6) causes a mismatch between server-rendered content and what the client actually needs.

Here's how to adjust your useDisplayItemsCount hook to resolve both:

import { useState, useEffect } from 'react';

// Keep your debounce function
const debounce = (func, delay) => {
  let timeoutId;
  return (...args) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
};

// Update this to check for window existence first
const determineDisplayItemsCount = () => {
  if (typeof window === 'undefined') return 6; // Fallback for server-side
  const width = window.innerWidth;
  
  // Replace with your actual breakpoint logic
  if (width < 640) return 1;
  if (width < 768) return 2;
  if (width < 1024) return 4;
  return 6;
};

export const useDisplayItemsCount = () => {
  // Use a server-safe initial value (matches server-side fallback)
  const [displayItemsCount, setDisplayItemsCount] = useState(6);

  useEffect(() => {
    const handleResize = debounce(() => {
      setDisplayItemsCount(determineDisplayItemsCount());
    }, 200);

    // Immediately calculate the correct value once the client mounts
    handleResize();

    // Listen for resize events
    window.addEventListener('resize', handleResize);

    // Cleanup on unmount
    return () => {
      window.removeEventListener('resize', handleResize);
      clearTimeout(handleResize.timeoutId);
    };
  }, []);

  return displayItemsCount;
};

Why this works:

  • Hydration fix: The server and client both start with the same initial value (6), so there's no content mismatch during hydration.
  • Correct initial value: Once the client mounts, useEffect runs immediately and updates the count to match the actual screen width—no need for user interaction.
  • Debounce remains: Your resize handler still avoids excessive re-renders.

Alternative Approach: Use Chakra UI's Built-in Hooks

Since you're already using Chakra UI, you can skip writing custom resize logic entirely by leveraging its breakpoint system. This is cleaner, avoids hydration issues out of the box, and aligns with Chakra's design philosophy.

First, make sure your Chakra theme defines the breakpoints you need (adjust values to match your requirements):

// theme.js
import { extendTheme } from '@chakra-ui/react';

const theme = extendTheme({
  breakpoints: {
    sm: '640px',
    md: '768px',
    lg: '1024px',
  },
});

export default theme;

Then, create a simplified hook using useMediaQuery to get the display count:

import { useMediaQuery } from '@chakra-ui/react';

export const useDisplayItemsCount = () => {
  const [isSm] = useMediaQuery('(min-width: 640px)');
  const [isMd] = useMediaQuery('(min-width: 768px)');
  const [isLg] = useMediaQuery('(min-width: 1024px)');

  // Map breakpoints to your desired item count
  if (isLg) return 6;
  if (isMd) return 4;
  if (isSm) return 2;
  return 1;
};

For your element width logic, you can use Chakra's useBreakpointValue to directly get the correct width without conditional checks:

import { useBreakpointValue } from '@chakra-ui/react';

// Inside your component
const itemWidth = useBreakpointValue({
  base: '90%',  // Smallest screens (count = 1)
  sm: '90%',    // sm breakpoint (count = 2)
  md: '70%',    // md breakpoint (count = 4)
  lg: '50%',    // lg breakpoint (count = 6)
});

Why this is better:

  • No manual window handling or debouncing—Chakra takes care of all that.
  • Built-in SSR support, so no hydration errors.
  • Breakpoints are centralized in your theme, making it easy to update values across your app.

Either approach will solve your original issues, but the Chakra-native method is more maintainable if you're already invested in the Chakra ecosystem.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:00:53