-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(react): ClientGate, IfElse, When, Mounted 인터페이스 개선 (#710)
- Loading branch information
Showing
10 changed files
with
145 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'@modern-kit/react': patch | ||
--- | ||
|
||
fix(react): ClientGate, IfElse, When, Mounted 인터페이스 개선 - @ssi02014 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,48 @@ | ||
import { PropsWithChildren, ReactNode, useSyncExternalStore } from 'react'; | ||
|
||
import { useSyncExternalStore } from 'react'; | ||
import { noop } from '@modern-kit/utils'; | ||
|
||
interface ClientGateProps { | ||
fallback?: JSX.Element; | ||
children: React.ReactNode; | ||
fallback?: React.ReactNode; | ||
} | ||
|
||
const subscribe = () => noop; | ||
const getSnapshot = () => false; | ||
const getServerSnapshot = () => true; | ||
|
||
/** | ||
* @description Client Side에서는 children을, Server Side에서는 fallback component를 보여주는 컴포넌트입니다. | ||
* @description `ClientGate`는 렌더링 환경에 따라 다른 컨텐츠를 보여주는 컴포넌트입니다: | ||
* - Client Side: `children` 컴포넌트를 렌더링 | ||
* - Server Side: `fallback` 컴포넌트를 렌더링 | ||
* | ||
* `CSR(Client-Side Rendering)` 환경에서는 컴포넌트가 마운트되기 전부터 children이 렌더링됩니다. | ||
* | ||
* 일반적인 `useEffect` 사용하여 클라이언트 사이드 렌더링을 감지할 경우, 다음과 같은 문제가 발생할 수 있습니다: | ||
* - 초기 렌더링에서 fallback이 표시됨 | ||
* - `useEffect` 실행 후 children으로 리렌더링되는 `이중 렌더링` 발생 | ||
* | ||
* `useSyncExternalStore`를 사용하여 서버와 클라이언트 간의 hydration mismatch를 방지합니다. | ||
* @see https://tkdodo.eu/blog/avoiding-hydration-mismatches-with-use-sync-external-store#usesyncexternalstore | ||
* | ||
* @param {ClientGateProps} props - 컴포넌트의 속성 | ||
* @param {JSX.Element} props.fallback - 서버 렌더링 시 표시할 대체 요소 | ||
* @param {React.ReactNode} props.children - 클라이언트에서 렌더링할 자식 요소 | ||
* @returns {React.ReactNode} - 서버에서는 fallback을, 클라이언트에서는 children을 반환 | ||
* @param {React.ReactNode} props.fallback - 서버 렌더링 시 표시할 대체 요소 | ||
* @returns {JSX.Element} - 서버에서는 fallback을, 클라이언트에서는 children을 반환 | ||
* | ||
* @example | ||
* <ClientGate fallback={<div>서버 환경입니다.</div>}> | ||
* <div>클라이언트 환경입니다.</div> | ||
* </ClientGate> | ||
*/ | ||
export function ClientGate({ | ||
fallback = <></>, | ||
fallback, | ||
children, | ||
}: PropsWithChildren<ClientGateProps>): ReactNode { | ||
}: ClientGateProps): JSX.Element { | ||
const isServer = useSyncExternalStore( | ||
subscribe, | ||
getSnapshot, | ||
getServerSnapshot | ||
); | ||
|
||
return isServer ? fallback : children; | ||
return <>{isServer ? fallback : children}</>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,26 @@ | ||
import { useIsMounted } from '../../hooks/useIsMounted'; | ||
|
||
interface MountedProps { | ||
fallback?: JSX.Element; | ||
children: React.ReactNode; | ||
fallback?: React.ReactNode; | ||
} | ||
|
||
export const Mounted = ({ | ||
fallback = <></>, | ||
children, | ||
}: React.PropsWithChildren<MountedProps>) => { | ||
/** | ||
* @description 컴포넌트가 마운트된 후에만 children을 렌더링하는 컴포넌트입니다. | ||
* | ||
* @param {MountedProps} props | ||
* @param {React.ReactNode} props.children - 마운트된 후 렌더링될 자식 컴포넌트 | ||
* @param {React.ReactNode} props.fallback - 마운트되기 전에 표시될 대체 컴포넌트 (선택사항) | ||
* @returns {JSX.Element} 마운트 상태에 따라 children 또는 fallback을 렌더링 | ||
* | ||
* @example | ||
* <Mounted fallback={<div>fallback component</div>}> | ||
* <div>children component</div> | ||
* </Mounted> | ||
*/ | ||
export const Mounted = ({ fallback, children }: MountedProps): JSX.Element => { | ||
const isMounted = useIsMounted(); | ||
|
||
if (!isMounted) return fallback; | ||
if (!isMounted) return <>{fallback}</>; | ||
return <>{children}</>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.