@teamsparta/hackle
Hackle 기능들을 Suspense와 함께 사용할 수 있도록 선언적인 훅과 컴포넌트를 제공하는 라이브러리입니다. 또한 타입 안정성을 개선했습니다.
설치
# pnpm
pnpm install @teamsparta/hackle
# yarn
yarn add @teamsparta/hackle
# npm
npm install @teamsparta/hackle
원격 구성
기존의 @hackler/react-sdk에서는 useLoadableRemoteConfig 훅을 사용하여 원격 구성을 가져왔었습니다.
import { Suspense } from 'react';
import { useLoadableRemoteConfig } from '@hackler/react-sdk';
function App() {
const { isLoading, remoteConfig } = useLoadableRemoteConfig('parameter-key');
const parameterValue = remoteConfig.get('parameter-key', 'default-value');
if (isLoading) return <Skeleton />;
return <div>{parameterValue}</div>;
}
위와 같이 useLoadableRemoteConfig 훅을 이용하면 다음과 같은 불편함이 생깁니다.
- 로딩 화면을 보여주기 위해서는 isLoading 값을 확인해야 하며, 코드가 명령적으로 작성됩니다.
- remoteConfig의 타입은 any로 추론됩니다.
@teamsparta/hackle에서는
isLoading이 true일 때 Promise를 반환합니다. 이를 통해 Suspense와 같이 결합하여 isLoading이 true일 때는 fallback을 보여줄 수 있습니다. 또한 제네릭을 사용하여 타입을 지정할 수 있습니다.
import { Suspense } from 'react';
import { useSuspenseRemoteConfig } from '@teamsparta/hackle';
function App() {
return (
<Suspense fallback={<Skeleton />}>
<Child />
</Suspense>
);
}
function Child() {
const {
data: { title, description },
} = useSuspenseRemoteConfig<{ title: string; description: string }>(
'remote-config-key',
);
return (
<div>
<h1>{title}</h1>
<p>{description}</p>
</div>
);
}
SuspenseRemoteConfig 컴포넌트를 사용하여 원격 구성 데이터를 자식 컴포넌트에게 넘겨줄 수도 있습니다. 이렇게 되면 자식 컴포넌트는 Presentational 컴포넌트로 작성할 수 있으며 훅의 제약으로부터 벗어날 수 있습니다.
function App() {
return (
<Suspense fallback={<Skeleton />}>
<SuspenseRemoteConfig<{
title: string;
description: string;
}> remoteConfigKey="remote-config-key">
{({ data }) => <Child {...data} />}
</SuspenseRemoteConfig>
</Suspense>
);
}
function Child({ title, description }: { title: string; description: string }) {
return (
<div>
<h1>{title}</h1>
<p>{description}</p>
</div>
);
}
A/B 테스트
기존의 @hackler/react-sdk에서는 HackleExperiment, HackleVariation 컴포넌트나 useLoadableVariationDetail 훅을 사용하여 테스트 그룹을 분배했었습니다.
- HackleExperiment, HackleVariation 컴포넌트를 사용했을 때
import {
HackleExperiment,
HackleVariation,
useLoadableVariationDetail,
} from '@hackler/react-sdk';
import { SwitchCase } from '@teamsparta/react';
function App() {
return (
<HackleExperiment experimentKey={42}>
<HackleVariation variation="A">
<A />
</HackleVariation>
<HackleVariation variation="B">
<B />
</HackleVariation>
<HackleVariation variation="C">
<B />
</HackleVariation>
</HackleExperiment>
);
}
- useLoadableVariationDetail 훅을 사용했을 때
import { useLoadableVariationDetail } from '@hackler/react-sdk';
import { SwitchCase } from '@teamsparta/react';
function App() {
const {
isLoading,
decision: { variation }, // variation의 타입은 string
} = useLoadableVariationDetail(42);
if (isLoading) return <Skeleton />;
return (
<SwitchCase value={variation} cases={{ A: <A />, B: <B />, C: <C /> }} />
);
}
위와 같이 코드를 작성하면 다음과 같은 불편함이 생깁니다.
- HackleExperiment, HackleVariation 컴포넌트를 사용하면 isLoading이 true일 때 fallback을 보여줄 수 없습니다.
- useLoadableVariationDetail 훅을 사용하면 로딩 화면을 보여주기 위해서는 isLoading 값을 확인해야 하며, 코드가 명령적으로 작성됩니다.
- 그리고 두 방법 공통적으로 variation의 타입이 ‘A’, ‘B’, ‘C’와 같은 문자열 리터럴이 아니라 string으로 추론됩니다.
@teamsparta/hackle에서는
isLoading이 true일 때 Promise를 반환합니다. 이를 통해 Suspense와 같이 결합하여 isLoading이 true일 때는 fallback을 보여줄 수 있습니다.
또한 hackle에서 테스트 그룹은 총 10개로 A부터 J까지 가능합니다. @teamsparta/hackle의 SuspenseVariation 컴포넌트와 useSuspenseVariation 훅의 variation은 string이 아니라 A부터 J까지의 문자열 리터럴로 추론됩니다.
- SuspenseVariation 컴포넌트를 사용했을 때
import { Suspense } from 'react';
import { useSuspenseVariation } from '@teamsparta/hackle';
import { SwitchCase } from '@teamsparta/react';
function App() {
return (
<Suspense fallback={<Skeleton />}>
<Child />
</Suspense>
);
}
function Child() {
const { variation } = useSuspenseVariation(42); // variation의 타입은 'A' ~ 'J'
return (
<SwitchCase value={variation} cases={{ A: <A />, B: <B />, C: <C /> }} />
);
}
- SuspenseVariation 컴포넌트를 사용했을 때
import { Suspense } from 'react';
import { useSuspenseVariation } from '@teamsparta/hackle';
import { SwitchCase } from '@teamsparta/react';
function App() {
return (
<SuspenseVariation experimentKey={42}>
{({ variation }) => (
<SwitchCase
value={variation}
cases={{ A: <A />, B: <B />, C: <C /> }}
/>
)}
</SuspenseVariation>
);
}