시나리오 (Scenario)
시나리오 기능은 복잡한 대화상자 흐름을 체계적으로 관리하고 재사용할 수 있게 해줍니다. 여러 단계의 대화상자나 조건부 흐름을 하나의 논리적 단위로 묶어 관리할 수 있습니다.
기본 객체 방식#
가장 간단하고 직관적인 방식으로, 객체 형태로 시나리오를 정의합니다:
// 로그인 시나리오 정의
const loginScenario = grunfeld.scenario("login", {
showLoginForm: () => {
grunfeld.add(() => ({
element: <LoginForm />,
position: "center",
}));
},
showLoading: () => {
grunfeld.remove(); // 이전 단계 정리
grunfeld.add(() => ({
element: "Loading...",
position: "center",
}));
},
showSuccess: () => {
grunfeld.remove();
grunfeld.add(() => ({
element: "로그인 성공!",
position: "top-right",
}));
},
});
// 사용법 - 동적 메서드 접근
await loginScenario.showLoginForm(); // 특정 단계 실행
await loginScenario.showLoading();
await loginScenario.showSuccess();
각 단계는 메서드로 호출할 수 있으며, Promise를 반환하므로 await를 사용하여 순차적으로 실행할 수 있습니다.
분리된 방식 (고급)#
제어 로직과 구현을 분리하여 더 복잡한 시나리오를 구성할 수 있습니다:
// 분리된 시나리오 정의
const advancedScenario = grunfeld.scenario(
"user-management",
// 제어 로직 (factory)
(cliche) => ({
processUser: async (user) => {
if (user.isPremium) {
await cliche.showPremiumContent();
} else {
await cliche.showBasicContent();
}
await cliche.logActivity();
},
}),
// 실제 구현 (implementation)
{
showPremiumContent: () => {
grunfeld.add(() => "프리미엄 콘텐츠");
},
showBasicContent: () => {
grunfeld.add(() => "기본 콘텐츠");
},
logActivity: () => {
console.log("사용자 활동 기록됨");
},
}
);
// 사용법
await advancedScenario.processUser({ isPremium: true });
이 방식은 비즈니스 로직과 UI 구현을 분리하여 유지보수성을 높여줍니다.
매개변수 전달#
시나리오 단계에 매개변수를 전달하여 동적인 동작을 구현할 수 있습니다:
// 매개변수를 받는 시나리오 정의
const userScenario = grunfeld.scenario("user-flow", {
welcomeUser: ({ userName, userType }) => {
grunfeld.add(() => ({
element: `${userName}님 (${userType}) 환영합니다!`,
position: "center",
}));
},
showDashboard: ({ permissions = [] }) => {
grunfeld.add(() => ({
element: `대시보드 (권한: ${permissions.join(", ")})`,
position: "center",
}));
},
});
// 개별 단계에 매개변수 전달 (동적 메서드 접근)
await userScenario.welcomeUser({
userName: "홍길동",
userType: "관리자",
});
await userScenario.showDashboard({
permissions: ["read", "write", "admin"],
});
사용자 입력 처리#
사용자 입력을 받아 다음 단계로 전달하거나 처리할 수 있습니다:
const registrationScenario = grunfeld.scenario("registration", {
getUserName: async () => {
const name = await grunfeld.add<string>((removeWith) => ({
element: (
<div>
<h3>이름을 입력하세요</h3>
<input
type="text"
onKeyPress={(e) => {
if (e.key === "Enter") {
removeWith(e.target.value);
}
}}
/>
</div>
),
position: "center",
}));
console.log("입력받은 이름:", name);
return name;
},
confirmData: async () => {
const confirmed = await grunfeld.add<boolean>((removeWith) => ({
element: (
<div>
<p>정보가 맞습니까?</p>
<button onClick={() => removeWith(true)}>확인</button>
<button onClick={() => removeWith(false)}>취소</button>
</div>
),
position: "center",
}));
if (!confirmed) {
throw new Error("사용자가 취소했습니다");
}
},
});
API 참조#
주요 시나리오 API 메서드:
scenario.step(name, params): 특정 단계 실행scenario.run(paramsMap): 모든 단계 순차 실행scenario.getSteps(): 단계 목록 반환scenario.hasStep(name): 단계 존재 여부 확인scenario.clone(newName): 시나리오 복제