Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useMountedState always returns false #2598

Open
AlejandroSanchez90 opened this issue Oct 11, 2024 · 1 comment
Open

useMountedState always returns false #2598

AlejandroSanchez90 opened this issue Oct 11, 2024 · 1 comment

Comments

@AlejandroSanchez90
Copy link

What is the current behavior?
this always returns false, im doing something wrong ?

'use client';
import React from 'react';
import { useTheme } from 'next-themes';
import { Moon, Sun } from 'lucide-react';
import { Button } from './ui/button';
import { useMountedState } from 'react-use';

export const ThemeToggler = () => {
  const { setTheme, theme } = useTheme();
  const isMounted = useMountedState();

  const isDark = theme === 'dark';

  const Icon = isDark ? Moon : Sun;

  const toggleTheme = () => {
    setTheme(isDark ? 'light' : 'dark');
  };

  // isMounted() is always false here
  if (!isMounted()) return null;

  return (
    <Button size={'icon'} variant={'ghost'} onClick={toggleTheme}>
      <Icon size={24} />
    </Button>
  );
};

Steps to reproduce it and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have extra dependencies other than react-use. Paste the link to your JSFiddle or CodeSandbox example below:

What is the expected behavior?

A little about versions:

  • OS:
  • Browser (vendor and version):
  • React:
  • react-use:
  • Did this worked in the previous package version?
@duran-0519
Copy link

duran-0519 commented Nov 14, 2024

The issue here is that useMountedState() from react-use returns a function that checks if the component is mounted, but it’s initially set to false. isMounted() will return false until the component is fully mounted on the client side.

A common solution to this in Next.js is to use a useEffect hook to check if the component has mounted. Alternatively, the next-themes library provides a resolvedTheme property that becomes available only after mounting. Here’s how you can modify your code to ensure it behaves as expected:

Use useEffect to set a mounted state.
Switch to resolvedTheme instead of theme to avoid the initial server-side mismatch.

'use client';
import React, { useEffect, useState } from 'react';
import { useTheme } from 'next-themes';
import { Moon, Sun } from 'lucide-react';
import { Button } from './ui/button';

export const ThemeToggler = () => {
  const { setTheme, resolvedTheme } = useTheme();
  const [isMounted, setIsMounted] = useState(false);

  useEffect(() => {
    setIsMounted(true);
  }, []);

  const isDark = resolvedTheme === 'dark';
  const Icon = isDark ? Moon : Sun;

  const toggleTheme = () => {
    setTheme(isDark ? 'light' : 'dark');
  };

  if (!isMounted) return null;

  return (
    <Button size={'icon'} variant={'ghost'} onClick={toggleTheme}>
      <Icon size={24} />
    </Button>
  );
};

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

No branches or pull requests

2 participants