Skip to content

Instantly share code, notes, and snippets.

@composite
Created April 26, 2022 09:44
Show Gist options
  • Select an option

  • Save composite/146392b5e7fb9f63f5ab9feebb75e625 to your computer and use it in GitHub Desktop.

Select an option

Save composite/146392b5e7fb9f63f5ab9feebb75e625 to your computer and use it in GitHub Desktop.
React Use Layout Context Hooks API Example
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];
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment