Skip to content

Commit

Permalink
feat(react): ClientOnly 컴포넌트 작업 완료 (#276)
Browse files Browse the repository at this point in the history
* feat(react): ClientOnly 컴포넌트 작업 완료

* Create clever-panthers-bake.md

* Update docs/docs/react/components/ClientOnly.mdx

---------

Co-authored-by: Gromit (전민재) <64779472+ssi02014@users.noreply.github.com>
  • Loading branch information
Sangminnn and ssi02014 authored Jun 28, 2024
1 parent 0873718 commit dbbaac5
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-panthers-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@modern-kit/react": minor
---

feat(react): ClientOnly 컴포넌트 작업 완료 - @Sangminnn
49 changes: 49 additions & 0 deletions docs/docs/react/components/ClientOnly.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { useState } from 'react';
import { ClientOnly } from '@modern-kit/react';

# ClientOnly

컴포넌트가 브라우저에 mount 되었을 때 children이 나타나게 해주는 컴포넌트입니다. 즉, children을 렌더링하는 환경이 클라이언트 환경임을 보장할 수 있습니다. mount 전에는 fallback으로 넣어준 컴포넌트를 보여줍니다.

`SSR` 환경에서 컴포넌트가 브라우저에 마운트되기 전과 후의 컴포넌트를 다루기 위해 사용할 수 있습니다.

<br />

## Code
[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/react/src/components/ClientOnly/index.tsx)

## Interface
```ts title="typescript"

interface ClientOnlyProps {
fallback?: JSX.Element;
}

const ClientOnly: ({
fallback = <></>
}: PropsWithChildren<ClientOnlyProps>) => JSX.Element;
```

## Usage
```tsx title="typescript"
import { ClientOnly } from '@modern-kit/react'

const Example = () => {
return (
<ClientOnly fallback={<div>mount가 완료되기 전입니다.</div>}>
<div>mount가 완료되었습니다.</div>
</ClientOnly>
);
};
```

## Example
export const Example = () => {
return (
<ClientOnly fallback={<div>mount가 완료되기 전입니다.</div>}>
<div>mount가 완료되었습니다.</div>
</ClientOnly>
);
};

<Example />
30 changes: 30 additions & 0 deletions packages/react/src/components/ClientOnly/ClientOnly.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { screen } from '@testing-library/react';

import { renderSetup } from '../../utils/test/renderSetup';
import { renderToString } from 'react-dom/server';

import { ClientOnly } from '.';

const TestComponent = () => {
return (
<ClientOnly fallback={<div>fallback component</div>}>
<div>children component</div>
</ClientOnly>
);
};

describe('ClientOnly', () => {
it('should render a fallback component before mount', () => {
const html = renderToString(<TestComponent />);

expect(html).toContain('fallback component');
expect(html).not.toContain('children component');
});

it('should render a children component after mount', () => {
renderSetup(<TestComponent />);

expect(screen.queryByText('fallback component')).not.toBeInTheDocument();
expect(screen.getByText('children component')).toBeInTheDocument();
});
});
15 changes: 15 additions & 0 deletions packages/react/src/components/ClientOnly/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useIsMounted } from '../../hooks/useIsMounted';

interface ClientOnlyProps {
fallback?: JSX.Element;
}

export const ClientOnly = ({
fallback = <></>,
children,
}: React.PropsWithChildren<ClientOnlyProps>) => {
const isMounted = useIsMounted();

if (!isMounted) return fallback;
return <>{children}</>;
};
1 change: 1 addition & 0 deletions packages/react/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './ClientOnly';
export * from './DebounceWrapper';
export * from './FallbackLazyImage';
export * from './InView';
Expand Down

0 comments on commit dbbaac5

Please sign in to comment.