AI Assistant
Stackflow Activity vs Step 완벽 가이드
🎯 Activity vs Step 명확한 구분 기준
핵심 판단 기준 4가지
1. 진입점 기준 (가장 중요)
- Activity: 여러 곳에서 직접 진입 가능
- Step: 특정 Activity에서만 진입 가능
// ✅ Activity - 다양한 곳에서 진입 가능
flow.push('ActLogin', {}); // 메인에서
flow.push('ActLogin', {}); // 설정에서
flow.push('ActLogin', {}); // 에러 발생시
// ✅ Step - 특정 Activity에서만 진입
// 로그인 Activity 내부에서만 접근
stepPush({ showPasswordReset: true });
2. URL/라우팅 기준
- Activity: 독립적인 URL을 가져야 함
- Step: URL 없이 상태로만 관리
// ✅ Activity
// /login
// /signup
// /dashboard
// ✅ Step
// /login (상태: showPasswordReset)
// /signup (상태: currentStep = 2)
3. 브라우저 히스토리 기준
- Activity: 뒤로가기 버튼으로 이전 Activity로 이동
- Step: 뒤로가기 시 이전 Step이나 Activity 내부 상태 변경
4. 재사용성 기준
- Activity: 앱의 다른 부분에서 재사용 가능
- Step: 특정 Activity에 종속되어 재사용 불가
📋 결정 체크리스트
다음 질문들로 판단하세요:
이 화면에 직접 링크를 걸 수 있나요?
- Yes → Activity / No → Step
앱의 다른 부분에서 이 화면으로 직접 이동할 일이 있나요?
- Yes → Activity / No → Step
이 화면이 독립적인 기능을 제공하나요?
- Yes → Activity / No → Step
브라우저 새로고침 시에도 이 화면이 유지되어야 하나요?
- Yes → Activity / No → Step
🏗️ Stackflow 기본 구조 이해
1. Activity 생성 방법
// MyActivity.tsx
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
const MyActivity: ActivityComponentType = () => {
return (
<AppScreen appBar={{ title: "My Activity" }}>
<div>My Activity</div>
</AppScreen>
);
};
export default MyActivity;
2. Stackflow 설정
// stackflow.ts
import { stackflow } from "@stackflow/react";
import { basicRendererPlugin } from "@stackflow/plugin-renderer-basic";
import { basicUIPlugin } from "@stackflow/plugin-basic-ui";
import MyActivity from "./MyActivity";
export const { Stack, useFlow } = stackflow({
transitionDuration: 350,
plugins: [
basicRendererPlugin(),
basicUIPlugin({
theme: "cupertino",
}),
],
activities: {
MyActivity,
},
initialActivity: () => "MyActivity", // 초기 Activity 설정
});
3. 파라미터가 있는 Activity
// Article.tsx
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
type ArticleParams = {
title: string;
};
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
</div>
</AppScreen>
);
};
export default Article;
🔄 Activity 네비게이션
Activity 이동 (push)
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
import { useFlow } from "./stackflow";
const MyActivity: ActivityComponentType = () => {
const { push } = useFlow();
const onClick = () => {
push("Article", {
title: "Hello",
});
};
return (
<AppScreen appBar={{ title: "My Activity" }}>
<div>
My Activity
<button onClick={onClick}>Go to article page</button>
</div>
</AppScreen>
);
};
Activity 교체 (replace)
const MyActivity: ActivityComponentType = () => {
const { replace } = useFlow();
const onClick = () => {
replace("Article", {
title: "Hello",
});
};
return (
<AppScreen appBar={{ title: "My Activity" }}>
<div>
My Activity
<button onClick={onClick}>Go to article page</button>
</div>
</AppScreen>
);
};
📚 Step 관리
Step 추가하기
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
import { useStepFlow } from "./stackflow";
type ArticleParams = {
title: string;
};
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
// 타입 안정성을 위해 현재 액티비티의 이름을 넣어줘요
const { stepPush } = useStepFlow("Article");
const onNextClick = () => {
// stepPush()을 호출하면 params.title이 변경돼요.
stepPush({
title: "Next Title",
});
};
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
<button onClick={onNextClick}>next</button>
</div>
</AppScreen>
);
};
Step 교체하기
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
const { stepReplace } = useStepFlow("Article");
const onChangeClick = () => {
// stepReplace()을 호출하면 params.title이 변경돼요
stepReplace({
title: "Next Title",
});
};
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
<button onClick={onChangeClick}>change</button>
</div>
</AppScreen>
);
};
Step 삭제하기
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
const { stepPop } = useStepFlow("Article");
const onPrevClick = () => {
// stepPop()을 호출하면 이전 params.title로 돌아가요
stepPop();
};
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
<button onClick={onPrevClick}>prev</button>
</div>
</AppScreen>
);
};
🎨 실제 프로젝트 적용 예제
로그인 관련 화면 구조
// 📁 프로젝트 구조
activities/
├── act-login.tsx // Activity
├── act-signup.tsx // Activity
├── act-dashboard.tsx // Activity
└── components/
├── login-form.tsx
├── password-reset-form.tsx // Step 내용
└── find-id-form.tsx // Step 내용
Activity 구현 예제
// act-login.tsx
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
import { useStepFlow } from "../stackflow";
import LoginForm from "../components/login-form";
import PasswordResetForm from "../components/password-reset-form";
import FindIdForm from "../components/find-id-form";
type LoginParams = {
step?: 'login' | 'resetPassword' | 'findId';
};
const ActLogin: ActivityComponentType<LoginParams> = ({ params }) => {
const { stepPush, stepPop } = useStepFlow("ActLogin");
const currentStep = params.step || 'login';
const showPasswordReset = () => {
stepPush({ step: 'resetPassword' });
};
const showFindId = () => {
stepPush({ step: 'findId' });
};
const goBack = () => {
stepPop();
};
return (
<AppScreen appBar={{ title: "로그인" }}>
{currentStep === 'login' && (
<LoginForm
onShowPasswordReset={showPasswordReset}
onShowFindId={showFindId}
/>
)}
{currentStep === 'resetPassword' && (
<PasswordResetForm onBack={goBack} />
)}
{currentStep === 'findId' && (
<FindIdForm onBack={goBack} />
)}
</AppScreen>
);
};
export default ActLogin;
Activity vs Step 분류 결과
// ✅ Activity로 분류된 화면들
- ActLogin (로그인)
- 이유: 메인, 보호된 페이지, 만료시 등 여러 곳에서 진입
- URL: /login
- ActSignup (회원가입)
- 이유: 로그인 페이지, 마케팅 페이지 등에서 진입
- URL: /signup
- ActDashboard (대시보드)
- 이유: 로그인 후 메인 화면, 독립적 접근 필요
- URL: /dashboard
// ✅ Step으로 분류된 화면들
- 비밀번호 찾기
- 이유: 로그인 페이지에서만 진입, URL 없음
- 구현: ActLogin의 step 파라미터로 관리
- 아이디 찾기
- 이유: 로그인 페이지에서만 진입, URL 없음
- 구현: ActLogin의 step 파라미터로 관리
- 본인인증
- 이유: 회원가입 과정의 한 단계
- 구현: ActSignup의 step 파라미터로 관리
🎯 핵심 정리
Activity를 사용해야 할 때
- 독립적인 URL이 필요한 경우
- 여러 곳에서 직접 접근해야 하는 경우
- 브라우저 새로고침 후에도 해당 화면이 유지되어야 하는 경우
- 앱의 주요 네비게이션 대상인 경우
Step을 사용해야 할 때
- 특정 Activity의 일부 과정인 경우
- 하나의 큰 기능을 여러 단계로 나누는 경우
- 이전/다음 단계의 맥락이 중요한 경우
- URL 없이 상태로만 관리해도 되는 경우
이 기준을 따르면 Stackflow에서 Activity와 Step을 명확하게 구분하여 사용할 수 있습니다.
Me
마크다운으로 작성해줘
AI Assistant
# Stackflow Activity vs Step 완벽 가이드
## 🎯 Activity vs Step 명확한 구분 기준
### 핵심 판단 기준 4가지
#### 1. **진입점 기준** (가장 중요)
- **Activity**: 여러 곳에서 직접 진입 가능
- **Step**: 특정 Activity에서만 진입 가능
typescript // ✅ Activity - 다양한 곳에서 진입 가능 flow.push('ActLogin', {}); // 메인에서 flow.push('ActLogin', {}); // 설정에서 flow.push('ActLogin', {}); // 에러 발생시 // ✅ Step - 특정 Activity에서만 진입 // 로그인 Activity 내부에서만 접근 stepPush({ showPasswordReset: true });
#### 2. **URL/라우팅 기준**
- **Activity**: 독립적인 URL을 가져야 함
- **Step**: URL 없이 상태로만 관리
typescript // ✅ Activity // /login // /signup // /dashboard // ✅ Step // /login (상태: showPasswordReset) // /signup (상태: currentStep = 2)
#### 3. **브라우저 히스토리 기준**
- **Activity**: 뒤로가기 버튼으로 이전 Activity로 이동
- **Step**: 뒤로가기 시 이전 Step이나 Activity 내부 상태 변경
#### 4. **재사용성 기준**
- **Activity**: 앱의 다른 부분에서 재사용 가능
- **Step**: 특정 Activity에 종속되어 재사용 불가
## 📋 결정 체크리스트
다음 질문들로 판단하세요:
1. **이 화면에 직접 링크를 걸 수 있나요?**
- Yes → Activity / No → Step
2. **앱의 다른 부분에서 이 화면으로 직접 이동할 일이 있나요?**
- Yes → Activity / No → Step
3. **이 화면이 독립적인 기능을 제공하나요?**
- Yes → Activity / No → Step
4. **브라우저 새로고침 시에도 이 화면이 유지되어야 하나요?**
- Yes → Activity / No → Step
## 🏗️ Stackflow 기본 구조 이해
### 1. Activity 생성 방법
typescript // MyActivity.tsx import { ActivityComponentType } from "@stackflow/react"; import { AppScreen } from "@stackflow/plugin-basic-ui"; const MyActivity: ActivityComponentType = () => { return ( <AppScreen appBar={{ title: "My Activity" }}> My Activity ); }; export default MyActivity;
### 2. Stackflow 설정
typescript // stackflow.ts import { stackflow } from "@stackflow/react"; import { basicRendererPlugin } from "@stackflow/plugin-renderer-basic"; import { basicUIPlugin } from "@stackflow/plugin-basic-ui"; import MyActivity from "./MyActivity"; export const { Stack, useFlow } = stackflow({ transitionDuration: 350, plugins: [ basicRendererPlugin(), basicUIPlugin({ theme: , activities: { MyActivity, }, initialActivity: () => "MyActivity", // 초기 Activity 설정 }); latex_unknown_tag
### 3. 파라미터가 있는 Activity
```typescript
// Article.tsx
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
type ArticleParams = {
title: string;
};
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
</div>
</AppScreen>
);
};
export default Article;
## 🔄 Activity 네비게이션
### Activity 이동 (push)
``` typescript
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
import { useFlow } from "./stackflow";
const MyActivity: ActivityComponentType = () => {
const { push } = useFlow();
const onClick = () => {
push("Article", {
title: "Hello",
});
};
return (
<AppScreen appBar={{ title: "My Activity" }}>
<div>
My Activity
<button onClick={onClick}>Go to article page</button>
</div>
</AppScreen>
);
};
Activity 교체 (replace)
const MyActivity: ActivityComponentType = () => {
const { replace } = useFlow();
const onClick = () => {
replace("Article", {
title: "Hello",
});
};
return (
<AppScreen appBar={{ title: "My Activity" }}>
<div>
My Activity
<button onClick={onClick}>Go to article page</button>
</div>
</AppScreen>
);
};
📚 Step 관리
Step 추가하기
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
import { useStepFlow } from "./stackflow";
type ArticleParams = {
title: string;
};
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
// 타입 안정성을 위해 현재 액티비티의 이름을 넣어줘요
const { stepPush } = useStepFlow("Article");
const onNextClick = () => {
// stepPush()을 호출하면 params.title이 변경돼요.
stepPush({
title: "Next Title",
});
};
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
<button onClick={onNextClick}>next</button>
</div>
</AppScreen>
);
};
Step 교체하기
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
const { stepReplace } = useStepFlow("Article");
const onChangeClick = () => {
// stepReplace()을 호출하면 params.title이 변경돼요
stepReplace({
title: "Next Title",
});
};
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
<button onClick={onChangeClick}>change</button>
</div>
</AppScreen>
);
};
Step 삭제하기
const Article: ActivityComponentType<ArticleParams> = ({ params }) => {
const { stepPop } = useStepFlow("Article");
const onPrevClick = () => {
// stepPop()을 호출하면 이전 params.title로 돌아가요
stepPop();
};
return (
<AppScreen appBar={{ title: "Article" }}>
<div>
<h1>{params.title}</h1>
<button onClick={onPrevClick}>prev</button>
</div>
</AppScreen>
);
};
🎨 실제 프로젝트 적용 예제
로그인 관련 화면 구조
📁 프로젝트 구조
activities/
├── act-login.tsx // Activity
├── act-signup.tsx // Activity
├── act-dashboard.tsx // Activity
└── components/
├── login-form.tsx
├── password-reset-form.tsx // Step 내용
└── find-id-form.tsx // Step 내용
Activity 구현 예제
// act-login.tsx
import { ActivityComponentType } from "@stackflow/react";
import { AppScreen } from "@stackflow/plugin-basic-ui";
import { useStepFlow } from "../stackflow";
import LoginForm from "../components/login-form";
import PasswordResetForm from "../components/password-reset-form";
import FindIdForm from "../components/find-id-form";
type LoginParams = {
step?: 'login' | 'resetPassword' | 'findId';
};
const ActLogin: ActivityComponentType<LoginParams> = ({ params }) => {
const { stepPush, stepPop } = useStepFlow("ActLogin");
const currentStep = params.step || 'login';
const showPasswordReset = () => {
stepPush({ step: 'resetPassword' });
};
const showFindId = () => {
stepPush({ step: 'findId' });
};
const goBack = () => {
stepPop();
};
return (
<AppScreen appBar={{ title: "로그인" }}>
{currentStep === 'login' && (
<LoginForm
onShowPasswordReset={showPasswordReset}
onShowFindId={showFindId}
/>
)}
{currentStep === 'resetPassword' && (
<PasswordResetForm onBack={goBack} />
)}
{currentStep === 'findId' && (
<FindIdForm onBack={goBack} />
)}
</AppScreen>
);
};
export default ActLogin;
Activity vs Step 분류 결과
// ✅ Activity로 분류된 화면들
- ActLogin (로그인)
- 이유: 메인, 보호된 페이지, 만료시 등 여러 곳에서 진입
- URL: /login
- ActSignup (회원가입)
- 이유: 로그인 페이지, 마케팅 페이지 등에서 진입
- URL: /signup
- ActDashboard (대시보드)
- 이유: 로그인 후 메인 화면, 독립적 접근 필요
- URL: /dashboard
// ✅ Step으로 분류된 화면들
- 비밀번호 찾기
- 이유: 로그인 페이지에서만 진입, URL 없음
- 구현: ActLogin의 step 파라미터로 관리
- 아이디 찾기
- 이유: 로그인 페이지에서만 진입, URL 없음
- 구현: ActLogin의 step 파라미터로 관리
- 본인인증
- 이유: 회원가입 과정의 한 단계
- 구현: ActSignup의 step 파라미터로 관리
🎯 핵심 정리
Activity를 사용해야 할 때
- 독립적인 URL이 필요한 경우
- 여러 곳에서 직접 접근해야 하는 경우
- 브라우저 새로고침 후에도 해당 화면이 유지되어야 하는 경우
- 앱의 주요 네비게이션 대상인 경우
Step을 사용해야 할 때
- 특정 Activity의 일부 과정인 경우
- 하나의 큰 기능을 여러 단계로 나누는 경우
- 이전/다음 단계의 맥락이 중요한 경우
- URL 없이 상태로만 관리해도 되는 경우
이 기준을 따르면 Stackflow에서 Activity와 Step을 명확하게 구분하여 사용할 수 있습니다.