Skip to content

Commit

Permalink
fix hydration errors
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMelior committed Apr 5, 2024
1 parent c1db1ea commit 80330ce
Show file tree
Hide file tree
Showing 14 changed files with 191 additions and 80 deletions.
5 changes: 3 additions & 2 deletions src/features/DropdownProfile/DropdownProfile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import { MoonIcon } from '@/shared/assets/icon/Moon';
import { SunIcon } from '@/shared/assets/icon/Sun';
import { MediaSize } from '@/shared/const';
import { Component } from '@/shared/lib/components';
import { Theme } from '@/shared/types/theme';
import {
Dropdown,
Expand Down Expand Up @@ -192,9 +193,9 @@ export const DropdownProfile: FC<DropdownProfileProps> = ({ children }) => {
)}
</DropdownMenu>
</Dropdown>
{isOpenModal && (
<Component isRender={isOpenModal}>
<ModalLogin isOpen={isOpenModal} onOpenChange={onOpenChangeModal} />
)}
</Component>
</>
);
};
106 changes: 56 additions & 50 deletions src/features/Search/ui/ModalSearch/ModalSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import { productData } from '@/db';
import { Cards } from '@/entities/Product';
import { SearchIcon } from '@/shared/assets/icon/Search';
import { DynamicModuleLoader, ReducersList } from '@/shared/lib/components';
import {
Component,
DynamicModuleLoader,
ReducersList,
} from '@/shared/lib/components';
import { Input } from '@/shared/ui/Input';
import {
Kbd,
Expand Down Expand Up @@ -47,56 +51,58 @@ const ModalSearch: FC<ModalSearchProps> = ({ isOpen, onOpenChange }) => {
});

return (
<DynamicModuleLoader reducers={initialReducers}>
<Modal
isOpen={isOpen}
onOpenChange={onOpenChange}
placement='center'
size='2xl'
scrollBehavior='inside'
className={cls.wrapper}
hideCloseButton
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className='flex flex-col gap-1'>
<Input
placeholder='Поиск'
autoFocus
variant='bordered'
onChange={(e) => {
dispatch(searchActions.setQuery(e.target.value));
}}
value={query}
startContent={<SearchIcon />}
endContent={
<Tooltip
closeDelay={0}
offset={5}
placement='top'
showArrow
content='Закрыть'
>
<Kbd
className={cls.kbd}
onClick={() => onOpenChange(true)}
<Component isRender={isOpen} delayClose={500}>
<DynamicModuleLoader reducers={initialReducers}>
<Modal
isOpen={isOpen}
onOpenChange={onOpenChange}
placement='center'
size='2xl'
scrollBehavior='inside'
className={cls.wrapper}
hideCloseButton
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className='flex flex-col gap-1'>
<Input
placeholder='Поиск'
autoFocus
variant='bordered'
onChange={(e) => {
dispatch(searchActions.setQuery(e.target.value));
}}
value={query}
startContent={<SearchIcon />}
endContent={
<Tooltip
closeDelay={0}
offset={5}
placement='top'
showArrow
content='Закрыть'
>
Esc
</Kbd>
</Tooltip>
}
/>
</ModalHeader>
<ModalBody>
<Cards size='sm' data={filteredProduct} />
</ModalBody>
{/* <ModalFooter></ModalFooter> */}
</>
)}
</ModalContent>
</Modal>
</DynamicModuleLoader>
<Kbd
className={cls.kbd}
onClick={() => onOpenChange(true)}
>
Esc
</Kbd>
</Tooltip>
}
/>
</ModalHeader>
<ModalBody>
<Cards size='sm' data={filteredProduct} />
</ModalBody>
{/* <ModalFooter></ModalFooter> */}
</>
)}
</ModalContent>
</Modal>
</DynamicModuleLoader>
</Component>
);
};

Expand Down
37 changes: 37 additions & 0 deletions src/shared/lib/components/Component/Component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { FC, ReactNode, useEffect, useState } from 'react';

interface ComponentProps {
isRender: boolean;
children: ReactNode;
delayOpen?: number;
delayClose?: number;
}

export const Component: FC<ComponentProps> = ({
isRender = true,
children,
delayOpen,
delayClose,
}) => {
const [shouldRender, setShouldRender] = useState(isRender);

useEffect(() => {
let timeoutId: NodeJS.Timeout;

if (!isRender) {
timeoutId = setTimeout(() => {
setShouldRender(false);
}, delayClose);
} else {
timeoutId = setTimeout(() => {
setShouldRender(true);
}, delayOpen);
}

return () => {
clearTimeout(timeoutId);
};
}, [delayClose, delayOpen, isRender]);

return shouldRender ? <>{children}</> : <></>;
};
3 changes: 2 additions & 1 deletion src/shared/lib/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Component } from './Component/Component';
import {
DynamicModuleLoader,
ReducersList,
} from './DynamicModuleLoader/DynamicModuleLoader';

export { DynamicModuleLoader };
export { Component, DynamicModuleLoader };
export type { ReducersList };
10 changes: 8 additions & 2 deletions src/shared/ui/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
Spinner,
useButton,
} from '@nextui-org/react';
import { CSSProperties, forwardRef, memo } from 'react';
import { CSSProperties, forwardRef, memo, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useMediaQuery } from 'react-responsive';
import cls from './Button.module.scss';
Expand Down Expand Up @@ -142,6 +142,12 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
[cls.selected]: isSelected,
};

const [isMounted, setMounted] = useState(false);

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

return (
<button
type='button'
Expand All @@ -159,7 +165,7 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
>
{lines && renderLinesItem()}
{renderButtonContent()}
{!disableRipple && !isOptimization && isMobile && (
{!disableRipple && !isOptimization && isMobile && isMounted && (
<div className='rippleRoot'>
<Ripple {...getRippleProps()} />
</div>
Expand Down
9 changes: 7 additions & 2 deletions src/shared/ui/SpaceCanvas/SpaceCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,14 @@ export const SpaceCanvas = memo(() => {
};
}, []);

if (!isVisible || theme === Theme.LIGHT || isMD || !isSpace) {
const [isMounted, setMounted] = useState(false);

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

if (!isVisible || theme === Theme.LIGHT || isMD || !isSpace || !isMounted)
return null;
}

return (
<div className={cn(cls.wrapper, 'noselect')}>
Expand Down
10 changes: 9 additions & 1 deletion src/views/FavoritesPage/FavoritesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { TopPage } from '@/widgets/TopPage';
import { Image } from '@nextui-org/react';
import cn from 'clsx';
import Link from 'next/link';
import { FC, memo } from 'react';
import { FC, memo, useEffect, useState } from 'react';
import cls from './FavoritesPage.module.scss';

export const FavoritesPage: FC = memo(() => {
Expand All @@ -29,6 +29,14 @@ export const FavoritesPage: FC = memo(() => {
// 0,
// );

const [isMounted, setMounted] = useState(false);

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

if (!isMounted) return;

return (
<div className={cn(cls.wrapper, 'content')}>
<TopPage
Expand Down
10 changes: 9 additions & 1 deletion src/widgets/Advantages/Advantages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import cn from 'clsx';
import { motion } from 'framer-motion';
import { useTheme } from 'next-themes';
import Image from 'next/image';
import { FC, memo } from 'react';
import { FC, memo, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import MediaQuery from 'react-responsive';
import cls from './Advantages.module.scss';
Expand All @@ -17,6 +17,14 @@ export const Advantages: FC = memo(() => {
const { theme } = useTheme();
const isOptimization = useSelector(getSettingsOptimization);

const [isMounted, setMounted] = useState(false);

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

if (!isMounted) return;

return (
<section className={cn(cls.wrapper, 'content')}>
<div className={cls.lines} data-optimization={isOptimization}>
Expand Down
10 changes: 8 additions & 2 deletions src/widgets/BestProduct/BestProduct.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Heading } from '@/widgets/Heading';
import cn from 'clsx';
import { motion } from 'framer-motion';
import { useTheme } from 'next-themes';
import { FC, memo, useRef } from 'react';
import { FC, memo, useEffect, useRef, useState } from 'react';
import { useMediaQuery } from 'react-responsive';
import 'swiper/css/autoplay';
import 'swiper/css/navigation';
Expand Down Expand Up @@ -51,9 +51,15 @@ export const BestProduct: FC = memo(() => {
);
}

const [isMounted, setMounted] = useState(false);

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

return (
<section className={cn(cls.wrapper, 'content')}>
{theme === 'dark' && (
{theme === 'dark' && isMounted && (
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
Expand Down
10 changes: 9 additions & 1 deletion src/widgets/Characteristics/Characteristics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useLocalstorageArray } from '@/shared/lib/hooks';
import { LocalstorageKeys } from '@/shared/types/localstorage';
import { Button } from '@/shared/ui/Button';
import cn from 'clsx';
import { FC, MouseEvent, memo } from 'react';
import { FC, MouseEvent, memo, useEffect, useState } from 'react';
import cls from './Characteristics.module.scss';

interface CharacteristicsProps {
Expand All @@ -18,6 +18,14 @@ export const Characteristics: FC<CharacteristicsProps> = memo(({ product }) => {
ProductDataProps['id']
>(LocalstorageKeys.LIKED, product.id);

const [isMounted, setMounted] = useState(false);

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

if (!isMounted) return;

return (
<ul className={cls.wrapper}>
{product.characteristics &&
Expand Down
14 changes: 9 additions & 5 deletions src/widgets/Navbar/ui/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,7 @@ export const Navbar = memo(
Поиск
{!isMD && <Kbd keys={['ctrl']}>K</Kbd>}
</Button>
{isOpen && (
<ModalSearch isOpen={isOpen} onOpenChange={onOpenChange} />
)}
<ModalSearch isOpen={isOpen} onOpenChange={onOpenChange} />
</>
),
[isMD, isOpen, onOpen, onOpenChange],
Expand Down Expand Up @@ -149,14 +147,20 @@ export const Navbar = memo(
);
};

const [isMounted, setMounted] = useState(false);

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

return (
<>
<header className={cn(cls.wrapper, className)}>
<nav className={cn(cls.content, 'content')}>
{isSM ? renderMobile() : renderDesktop()}
{isSM && isMounted ? renderMobile() : isMounted && renderDesktop()}
</nav>
</header>
{isSM && renderSearch()}
{isSM && isMounted && renderSearch()}
<div className={cls.spacer} />
</>
);
Expand Down
9 changes: 7 additions & 2 deletions src/widgets/Ready/Ready.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@ import { motion } from 'framer-motion';
import { useTheme } from 'next-themes';
import Image from 'next/image';
import Link from 'next/link';
import { FC, memo } from 'react';
import { FC, memo, useEffect, useState } from 'react';
import cls from './Ready.module.scss';

export const Ready: FC = memo(() => {
const [isMounted, setMounted] = useState(false);
const { theme } = useTheme();

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

return (
<div className={cn(cls.wrapper, 'content')}>
<Button
Expand Down Expand Up @@ -43,7 +48,7 @@ export const Ready: FC = memo(() => {
Найти подарок
</Button>
</Link>
{theme === 'dark' && (
{theme === 'dark' && isMounted && (
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
Expand Down
Loading

0 comments on commit 80330ce

Please sign in to comment.