Skip to content

Commit

Permalink
feat: 공용 swiper 모듈이 여러개 일때도 사용할수 있도록 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-yn committed Feb 26, 2024
1 parent 14d72da commit e4b1f89
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 36 deletions.
11 changes: 6 additions & 5 deletions src/components/OceanSwiper/OceanSwiper.context.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { createStaticContext } from '@/utils/context/StaticContext';

export interface ContextDispatchOceanSwiperProps {}

interface ContextOceanSwiper {
swiperWrapperRef: {
current: HTMLDivElement | null;
};
buttonRefs: {
prev: HTMLButtonElement | null;
next: HTMLButtonElement | null;
};
}

export const ContextDispatchOceanSwiper =
createStaticContext<ContextDispatchOceanSwiperProps>({});

export const ContextValueOceanSwiper = createStaticContext<ContextOceanSwiper>({
swiperWrapperRef: {
current: null,
},
buttonRefs: {
prev: null,
next: null,
Expand Down
56 changes: 35 additions & 21 deletions src/components/OceanSwiper/OceanSwiper.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,48 @@
'use client';

import React, { PropsWithChildren, useEffect, useRef, useState } from 'react';
import React, { PropsWithChildren, useEffect, useRef } from 'react';
import { A11y } from 'swiper/modules';
import { Swiper, SwiperRef, SwiperSlide, useSwiper } from 'swiper/react';
import { SwiperOptions } from 'swiper/types';
import Tag from '@/composable/Tag/Tag';
import { customEvents } from '@/const/customEvents';
import { getStaticContext } from '@/utils/context/StaticContext';
import {
ContextDispatchOceanSwiper,
ContextValueOceanSwiper,
} from './OceanSwiper.context';

// TODO : 이벤트 위임 구현과 UI 컨트롤 로직을 위한 컨텍스트 API 사용
import { ContextValueOceanSwiper } from './OceanSwiper.context';

const OceanSwiper = ({ children }: PropsWithChildren) => {
return (
<ContextDispatchOceanSwiper.Provider value={{}}>
<ContextValueOceanSwiper.Provider
value={{
buttonRefs: {
prev: null,
next: null,
},
}}
>
<div>{children}</div>
</ContextValueOceanSwiper.Provider>
</ContextDispatchOceanSwiper.Provider>
<ContextValueOceanSwiper.Provider
value={{
swiperWrapperRef: {
current: null,
},
buttonRefs: {
prev: null,
next: null,
},
}}
>
<OceanSwiper.Wrap>{children}</OceanSwiper.Wrap>
</ContextValueOceanSwiper.Provider>
);
};

const Wrap = ({ children }: PropsWithChildren) => {
const { swiperWrapperRef } = getStaticContext(ContextValueOceanSwiper);
const divRef = useRef<HTMLDivElement>(null);

useEffect(() => {
swiperWrapperRef.current = divRef.current;
typeof window !== 'undefined' &&
window.dispatchEvent(
new CustomEvent(customEvents.SWIPER_INIT, {
detail: swiperWrapperRef.current,
}),
);
}, []);
return <div ref={divRef}>{children}</div>;
};

interface MainProps extends SwiperOptions {
hiddenNavigation?: boolean;
prevButton?: React.ReactNode;
Expand All @@ -44,6 +56,7 @@ const Main = ({
nextButton,
...rest
}: PropsWithChildren<MainProps>) => {
const { swiperWrapperRef } = getStaticContext(ContextValueOceanSwiper);
const swiperRef = useRef<SwiperRef | null>(null);

return (
Expand All @@ -53,8 +66,8 @@ const Main = ({
modules={[A11y]}
slidesPerView={1}
onRealIndexChange={(e) => {
typeof window !== 'undefined' &&
window.dispatchEvent(
swiperWrapperRef.current &&
swiperWrapperRef.current.dispatchEvent(
new CustomEvent(customEvents.SWIPER_REAL_INDEX_CHANGE, {
detail: e,
}),
Expand Down Expand Up @@ -116,6 +129,7 @@ const Button = ({ className, style, direction, hidden }: ButtonProps) => {
);
};

OceanSwiper.Wrap = Wrap;
OceanSwiper.Top = Tag;
OceanSwiper.Main = Main;
OceanSwiper.Slide = SwiperSlide;
Expand Down
1 change: 1 addition & 0 deletions src/const/customEvents.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const customEvents = {
SWIPER_REAL_INDEX_CHANGE: 'SWIPER_REAL_INDEX_CHANGE',
SWIPER_INIT: 'SWIPER_INIT',
} as const;
12 changes: 6 additions & 6 deletions src/hook/useEventListener.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from 'react';

const useEventListener = <T extends Event>(
target: EventTarget | undefined,
target: EventTarget | undefined | null,
event: string,
callback: (event: T) => void,
options?: boolean | AddEventListenerOptions,
Expand All @@ -11,13 +11,13 @@ const useEventListener = <T extends Event>(
};

useEffect(() => {
typeof target !== 'undefined' &&
target.addEventListener(event, eventListener, options);
if (!target) return;

target.addEventListener(event, eventListener, options);
return () => {
typeof target !== 'undefined' &&
target.removeEventListener(event, eventListener, options);
target.removeEventListener(event, eventListener, options);
};
}, []);
}, [target]);
};

export default useEventListener;
26 changes: 22 additions & 4 deletions src/hook/useOceanSwiperIndex.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import Swiper from 'swiper';
import { ContextValueOceanSwiper } from '@/components/OceanSwiper/OceanSwiper.context';
import { customEvents } from '@/const/customEvents';
import { getStaticContext } from '@/utils/context/StaticContext';
import { eventManager } from '@/utils/eventManager';
import useEventListener from './useEventListener';

export const useOceanSwiperIndex = () => {
const { swiperWrapperRef } = getStaticContext(ContextValueOceanSwiper);
const [readIndex, setIndex] = useState(0);

useEventListener<CustomEvent<Swiper>>(
typeof window !== 'undefined' ? window : undefined,
const { add, remove } = eventManager(
swiperWrapperRef,
customEvents.SWIPER_REAL_INDEX_CHANGE,
(e) => {
setIndex(e.detail.realIndex);
setIndex((e as CustomEvent<Swiper>).detail.realIndex);
},
);

useEventListener<CustomEvent<HTMLDivElement>>(
typeof window !== 'undefined' ? window : null,
customEvents.SWIPER_INIT,
(e) => {
if (e.detail === swiperWrapperRef.current) add();
},
);

useEffect(() => {
return () => {
remove();
};
}, []);

return { readIndex };
};
27 changes: 27 additions & 0 deletions src/utils/eventManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export const eventManager = <T extends Event>(
target: {
current: EventTarget | null;
},
event: string,
callback: (event: T) => void,
options?: boolean | AddEventListenerOptions,
) => {
const eventListener: EventListener = (event: Event) => {
return callback(event as T);
};

const add = () => {
if (target.current)
target.current.addEventListener(event, eventListener, options);
};

const remove = () => {
if (target.current)
target.current.removeEventListener(event, eventListener, options);
};

return {
add,
remove,
};
};

0 comments on commit e4b1f89

Please sign in to comment.