Created
April 26, 2022 09:44
-
-
Save composite/146392b5e7fb9f63f5ab9feebb75e625 to your computer and use it in GitHub Desktop.
React Use Layout Context Hooks API Example
This file contains hidden or 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
| import type React from 'react'; | |
| import { createContext, useContext, useEffect, useMemo, useState } from 'react'; | |
| /** | |
| * 레이아웃 키값 Map | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @export | |
| * @interface LayoutMap | |
| * @typedef {LayoutMap} | |
| */ | |
| export interface LayoutMap { | |
| /** | |
| * 키에 대한 컴포넌트 참조 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| */ | |
| [key: string]: React.ElementType; | |
| } | |
| /** | |
| * 레이아웃 Base | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @interface UseLayoutBase | |
| * @typedef {UseLayoutBase} | |
| */ | |
| interface UseLayoutBase { | |
| /** | |
| * 레이아웃 컴포넌트 Map | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @type {LayoutMap} | |
| */ | |
| layoutMap: LayoutMap; | |
| } | |
| /** | |
| * 레이아웃 범용 데이터 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @export | |
| * @interface UseLayoutData | |
| * @typedef {UseLayoutData} | |
| */ | |
| export interface UseLayoutData { | |
| /** | |
| * 레이아웃 이름 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @type {string} | |
| */ | |
| layoutName: string; | |
| /** | |
| * 레이아웃에 쓰일 속성 모음 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @type {?React.ComponentProps<any>} | |
| */ | |
| layoutProps?: React.ComponentProps<any>; | |
| /** | |
| * 레이아웃과 컴포넌트에 공유할 데이터 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @type {?unknown} | |
| */ | |
| layoutData?: unknown; | |
| } | |
| /** | |
| * 레이아웃 컨텍스트 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @interface UseLayoutContext | |
| * @typedef {UseLayoutContext} | |
| * @extends {UseLayoutData} | |
| */ | |
| interface UseLayoutContext extends UseLayoutData { | |
| /** | |
| * 레이아웃 변경 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @type {(data: UseLayoutData) => void} | |
| */ | |
| changeLayout: (data: UseLayoutData) => void; | |
| } | |
| /** | |
| * 레이아웃 제공자 속성 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @export | |
| * @typedef {UseLayoutProps} | |
| */ | |
| export type UseLayoutProps = UseLayoutBase & UseLayoutData; | |
| /** | |
| * useLayout 계열의 결과물 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @export | |
| * @typedef {UseLayoutResult} | |
| */ | |
| export type UseLayoutResult = [string, React.ComponentProps<any>, unknown]; | |
| /** | |
| * 레이아웃 컨텍스트 생성기 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @type {*} | |
| */ | |
| const LayoutContext = createContext({ | |
| layoutName: '', | |
| layoutProps: undefined, | |
| layoutData: undefined, | |
| changeLayout: () => void 0, | |
| } as UseLayoutContext); | |
| /** | |
| * 레이아웃 정의가 없을 경우에 대비한 빈 레이아웃 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @param {React.PropsWithChildren<any>} { children } | |
| * @returns {*} | |
| */ | |
| const EmptyLayout = ({ children }: React.PropsWithChildren<any>) => ( | |
| <>{children}</> | |
| ); | |
| /** | |
| * 레이아웃 제공자 컴포넌트. 레이아웃 적용할 곳에 적용. | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @param {React.PropsWithChildren<UseLayoutProps>} { | |
| children, | |
| layoutName, | |
| layoutMap, | |
| } | |
| * @returns {JSX.Element} | |
| */ | |
| export const LayoutProvider = ({ | |
| children, | |
| layoutName, | |
| layoutMap, | |
| }: React.PropsWithChildren<UseLayoutProps>) => { | |
| if ( | |
| layoutMap === undefined || | |
| layoutMap == null || | |
| !Object.keys(layoutMap).length | |
| ) | |
| layoutMap = { '': EmptyLayout }; | |
| const layoutKeys = Object.keys(layoutMap); | |
| if (!layoutKeys.includes(layoutName)) layoutName = layoutKeys[0]; | |
| const [current, change] = useState<UseLayoutData>({ | |
| layoutName, | |
| }); | |
| const LayoutWrapper = useMemo(() => { | |
| return layoutMap[ | |
| layoutKeys.includes(current.layoutName) | |
| ? current.layoutName | |
| : layoutKeys[0] | |
| ]; | |
| }, [current.layoutName]); | |
| return ( | |
| <LayoutContext.Provider | |
| value={{ | |
| ...current, | |
| changeLayout: change, | |
| }} | |
| > | |
| <LayoutWrapper {...current.layoutProps}>{children}</LayoutWrapper> | |
| </LayoutContext.Provider> | |
| ); | |
| }; | |
| /** | |
| * 현재 레이아웃 데이터 취득 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @returns {UseLayoutResult} | |
| */ | |
| export const useLayoutState = (): UseLayoutResult => { | |
| const { layoutName, layoutProps, layoutData } = useContext(LayoutContext); | |
| return [layoutName, layoutProps, layoutData]; | |
| }; | |
| /** | |
| * 레이아웃을 변경하고 변경 전 데이터 취득 | |
| * @date 2022. 4. 20. - 오후 3:51:50 | |
| * | |
| * @param {UseLayoutData} args | |
| * @returns {UseLayoutResult} | |
| */ | |
| export const useChangeLayout = (args: UseLayoutData): UseLayoutResult => { | |
| const { layoutName, layoutProps, layoutData, changeLayout } = | |
| useContext(LayoutContext); | |
| useEffect(() => { | |
| if (args.layoutName !== undefined && args.layoutName != null) | |
| changeLayout(args); | |
| }, [changeLayout]); | |
| return [layoutName, layoutProps, layoutData]; | |
| }; |
This file contains hidden or 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
| // TODO |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment