Forma
High-performance and developer-friendly React form state management library
고성능이며 개발자 친화적인 React 폼 상태 관리 라이브러리
Forma is a high-performance library that makes form and state management in React applications simple yet powerful. Start immediately with Zero-Config, and achieve optimal performance through selective re-rendering via individual field subscriptions. Easily access production-level advanced features like global form state sharing, Dot Notation nested object access, and full MUI compatibility without complex setup.
Forma는 React 애플리케이션에서 폼과 상태를 간편하면서도 강력하게 관리할 수 있는 고성능 라이브러리입니다. Zero-Config로 바로 시작할 수 있으며, 개별 필드 구독을 통한 선택적 리렌더링으로 최적의 성능을 제공합니다. 복잡한 설정 없이도 글로벌 폼 상태 공유, Dot Notation 중첩 객체 접근, MUI 완전 호환 등 프로덕션 레벨의 고급 기능들을 손쉽게 사용할 수 있습니다.
Why Forma? | 왜 Forma인가?
Forma는 단순한 폼 라이브러리가 아닙니다. React 상태 관리의 패러다임을 바꾸는 혁신적인 솔루션입니다.
🚀 The Ultimate State Management Solution | 최강의 상태 관리 솔루션
1. Watch + Actions = No More useEffect & useState & Context
useEffect, useState, Context 지옥에서 탈출하세요
// ❌ Traditional: useEffect + useState + Context + Props Drilling
const AuthContext = createContext(null);
function App() {
const [logined, setLogined] = useState(false);
const [syncInterval, setSyncInterval] = useState(null);
useEffect(() => {
if (logined) {
const interval = setInterval(() => syncData(), 5000);
setSyncInterval(interval);
} else {
if (syncInterval) clearInterval(syncInterval);
setSyncInterval(null);
}
}, [logined]);
// Props drilling or Context Provider needed
return (
<AuthContext.Provider value={{ logined, setLogined }}>
<Header />
<Main />
<Footer />
</AuthContext.Provider>
);
}
// ✅ Forma: Clean and declarative
const state = useGlobalFormaState({
stateId: "auth",
initialValues: {
logined: false,
user: { name: "", email: "" },
syncInterval: null,
},
actions: {
startSync: (ctx) => {
const interval = setInterval(() => syncData(), 5000);
ctx.setValue("syncInterval", interval);
},
stopSync: (ctx) => {
const interval = ctx.getValue("syncInterval");
if (interval) clearInterval(interval);
ctx.setValue("syncInterval", null);
},
},
watch: {
logined: (ctx, value) => {
value ? ctx.actions.startSync(ctx) : ctx.actions.stopSync(ctx);
},
"user.email": (ctx, value) => {
console.log("Email changed:", value);
},
},
});Benefits | 이점:
- 🧹 No useEffect clutter | useEffect 없이 깔끔한 코드
- � No Context needed | Context API 불필요
- 🎯 No Props Drilling | Props 전달 지옥 탈출
- �📦 Modular logic | 로직을 별도 파일로 분리 가능
- 🧪 Easy testing | actions/watch 단독 테스트 용이
- 🎯 Better code cohesion | 높은 코드 응집도
2. Surgical Re-rendering
수술적 정밀도의 리렌더링
// ❌ Redux/Context: Entire component re-renders
const { user, todos, settings } = useStore(); // or useContext(AppContext)
// All fields change = entire component re-renders
// ✅ Forma: Only what you need
const userName = state.useValue("user.name"); // Only this field
const todoCount = state.useValue("todos.length"); // Only array length
const theme = state.useValue("settings.theme"); // Only theme
// Each component subscribes to ONLY what it needsPerformance | 성능:
- ⚡ 10-100x faster than Redux for large forms | 대규모 폼에서 Redux 대비 10-100배 빠름
- 🎯 Field-level optimization | 필드 단위 최적화
- 📊 No selectors needed | 셀렉터 불필요
- 🔥 Zero wasted renders | 불필요한 렌더링 제로
3. Form + State + Global Access in One
폼, 상태, 글로벌 접근을 하나로
// ❌ Traditional: Multiple libraries + Context boilerplate
import { useForm } from "react-hook-form";
import { create } from "zustand";
import { createContext, useContext } from "react";
// Context setup, Provider wrapping, Props drilling...
const FormContext = createContext(null);
function App() {
const form = useForm();
return (
<FormContext.Provider value={form}>
<Header />
<MainContent />
</FormContext.Provider>
);
}
// ✅ Forma: One library, zero boilerplate
import { useGlobalForm, useGlobalFormaState } from "@ehfuse/forma";
function Header() {
// Access anywhere, no Provider needed!
const state = useGlobalFormaState<AuthState>({ stateId: "auth" });
const userName = state.useValue("user.name");
}
function MainContent() {
// Same state, no props drilling
const state = useGlobalFormaState<AuthState>({ stateId: "auth" });
}All-in-One | 올인원:
- 📝 Form management | 폼 관리
- 🌐 Global state (no Context!) | 전역 상태 (Context 불필요!)
- 🚫 No Props Drilling | Props 전달 불필요
- 👀 Reactive watch | 반응형 감시
- 🎬 Actions system | 액션 시스템
- 🎭 Modal management | 모달 관리
- 📱 Breakpoint detection | 반응형 감지
Key Features | 주요 특징
- 🎯 Zero-Config: Start immediately | 설정 없이 즉시 시작
- 👀 Watch System: Replace useEffect with declarative watchers | useEffect를 선언적 watcher로 대체
- � Actions Pattern: Modular business logic | 모듈화된 비즈니스 로직
- ✅ Individual Field Subscription: Surgical re-rendering | 수술적 리렌더링
- 🌟 Dot Notation: Deep nested access
user.profile.name| 깊은 중첩 접근 - 🌐 Global State Sharing: Share across components | 컴포넌트 간 공유
- 🎭 Modal Stack: Mobile-friendly with back button | 뒤로가기 지원 모달
- 📱 Breakpoint Management: Responsive UI made easy | 반응형 UI 간편화
- ✅ Full MUI Compatibility: Perfect Material-UI integration | MUI 완벽 통합
- ✅ TypeScript Native: Full type safety | 완전한 타입 안전성
Documentation | 문서
English
- Getting Started Guide - Step-by-step tutorial and examples
- API Reference - Complete API documentation with examples
- Examples Collection - Practical usage examples and patterns
- Performance Guide - Performance optimization techniques
- Performance Warnings - Anti-patterns and common pitfalls
- Migration Guide - Migrate from other form libraries
- useGlobalForm Guide - Global form state management
- Global Hooks Comparison - useGlobalForm vs useGlobalFormaState
- Library Comparison - Forma vs other libraries
한국어 (Korean)
- 시작 가이드 - 단계별 튜토리얼과 예제
- API 레퍼런스 - 완전한 API 문서와 예제
- 예제 모음 - 실용적인 사용 예제와 패턴
- 성능 최적화 가이드 - 성능 최적화 기법
- 성능 최적화 주의사항 - 안티패턴과 일반적인 함정
- 마이그레이션 가이드 - 다른 폼 라이브러리에서 이전
- useGlobalForm 가이드 - 글로벌 폼 상태 관리
- 글로벌 훅 비교 - useGlobalForm vs useGlobalFormaState
- 라이브러리 비교 - Forma vs 다른 라이브러리
Links | 링크
링크
Installation | 설치
npm install @ehfuse/formayarn add @ehfuse/formaQuick Start | 빠른 시작
npm install @ehfuse/formaReal-World Example: Todo App with Watch | 실전 예제: Watch를 활용한 Todo 앱
import { useGlobalFormaState } from "@ehfuse/forma";
// 🎯 Separate actions file for better organization
// 액션을 별도 파일로 분리하여 코드 응집도 향상
const todoActions = {
addTodo: (ctx, text: string) => {
const todos = ctx.values.todos;
ctx.setValue("todos", [
...todos,
{
id: Date.now(),
text,
completed: false,
},
]);
},
toggleTodo: (ctx, id: number) => {
const todos = ctx.values.todos.map((t) =>
t.id === id ? { ...t, completed: !t.completed } : t
);
ctx.setValue("todos", todos);
},
// Auto-save to localStorage
saveToStorage: (ctx) => {
localStorage.setItem("todos", JSON.stringify(ctx.values.todos));
},
};
function TodoApp() {
const state = useGlobalFormaState({
stateId: "todo-app",
initialValues: {
todos: [],
filter: "all",
lastSync: null,
},
actions: todoActions,
watch: {
// 👀 Auto-save when todos change (replaces useEffect!)
// todos 변경 시 자동 저장 (useEffect 불필요!)
todos: (ctx, value) => {
ctx.actions.saveToStorage(ctx);
ctx.setValue("lastSync", new Date().toISOString());
},
// 🎯 Log filter changes
filter: (ctx, value, prevValue) => {
console.log(`Filter changed: ${prevValue} → ${value}`);
},
},
});
// ✅ Surgical re-rendering: Only subscribes to what's needed
// 수술적 리렌더링: 필요한 것만 구독
const todosLength = state.useValue("todos.length");
const filter = state.useValue("filter");
const lastSync = state.useValue("lastSync");
return (
<div>
<h1>Todos ({todosLength})</h1>
<p>Last synced: {lastSync}</p>
<button onClick={() => state.actions.addTodo(state, "New Task")}>
Add Todo
</button>
<select
value={filter}
onChange={(e) => state.setValue("filter", e.target.value)}
>
<option value="all">All</option>
<option value="active">Active</option>
<option value="completed">Completed</option>
</select>
</div>
);
}What you gain | 얻는 것:
- 🧹 No useEffect - Watch handles all side effects | useEffect 제거 - Watch가 모든 부수효과 처리
- 📦 Modular actions - Easy to test and maintain | 모듈화된 액션 - 테스트와 유지보수 용이
- ⚡ Optimized rendering - Only
todosLength,filter,lastSynctrigger re-renders | 최적화된 렌더링 - 🔄 Automatic persistence - Watch auto-saves changes | 자동 저장 - Watch가 변경사항 자동 저장
When to choose Forma?
Forma is specialized for form state management and shines in specific scenarios. Here's when Forma is the perfect choice for your project.
Perfect for these use cases:
🎨 MUI (Material-UI) Projects
- Seamless integration with MUI components
- No additional wrapper components needed
- Built-in support for MUI's controlled component patterns
⚡ Performance-Critical Forms
- Large forms with many fields (50+ inputs)
- Real-time data visualization forms
- Forms that update frequently during user interaction
🔄 Multi-Step & Global Forms
- Wizard-style multi-step forms
- Forms shared across multiple components
- Registration flows with data persistence
🏗️ Complex Nested Data
- User profiles with nested address/contact info
- Product configurations with multiple layers
- Settings panels with grouped options
📊 Dynamic Form Generation
- Forms generated from API schemas
- Conditional field rendering
- Dynamic validation rules
언제 Forma를 선택해야 할까요?
Forma는 폼 상태 관리에 특화된 라이브러리로 특정 시나리오에서 빛을 발합니다. 다음은 Forma가 프로젝트에 완벽한 선택이 되는 경우입니다.
이런 경우에 완벽합니다:
🎨 MUI (Material-UI) 프로젝트
- MUI 컴포넌트와 완벽한 통합
- 추가 래퍼 컴포넌트 불필요
- MUI의 제어 컴포넌트 패턴 내장 지원
⚡ 성능이 중요한 폼
- 많은 필드가 있는 대규모 폼 (50개 이상 입력)
- 실시간 데이터 시각화 폼
- 사용자 상호작용 중 자주 업데이트되는 폼
🔄 멀티 스텝 & 글로벌 폼
- 마법사 스타일의 멀티 스텝 폼
- 여러 컴포넌트에서 공유되는 폼
- 데이터 지속성이 있는 등록 플로우
🏗️ 복잡한 중첩 데이터
- 중첩된 주소/연락처 정보가 있는 사용자 프로필
- 다층 구조의 제품 구성
- 그룹화된 옵션이 있는 설정 패널
📊 동적 폼 생성
- API 스키마에서 생성되는 폼
- 조건부 필드 렌더링
- 동적 검증 규칙
Architecture Benefits | 아키텍처 이점
📁 Clean Separation of Concerns | 관심사의 명확한 분리
// actions.ts - Business logic isolated
// actions.ts - 비즈니스 로직 분리
export const authActions = {
login: async (ctx, credentials) => {
const user = await api.login(credentials);
ctx.setValues({ logined: true, user, token: user.token });
},
logout: (ctx) => {
ctx.setValues({ logined: false, user: null, token: null });
},
startSync: (ctx) => {
/* ... */
},
stopSync: (ctx) => {
/* ... */
},
};
// watch.ts - Side effects isolated
// watch.ts - 부수효과 분리
export const authWatch = {
logined: (ctx, value) => {
value ? ctx.actions.startSync(ctx) : ctx.actions.stopSync(ctx);
},
"user.preferences": (ctx, value) => {
localStorage.setItem("prefs", JSON.stringify(value));
},
};
// component.tsx - Pure UI
// component.tsx - 순수 UI
function AuthApp() {
const state = useGlobalFormaState({
stateId: "auth",
actions: authActions,
watch: authWatch,
});
// Clean, declarative UI
// 깔끔한 선언적 UI
return <LoginForm onSubmit={state.actions.login} />;
}Benefits | 이점:
- 🧪 Testable: Test actions/watch independently | 독립적 테스트 가능
- 📦 Reusable: Share logic across projects | 프로젝트 간 로직 공유
- 🔍 Maintainable: Easy to locate and update logic | 로직 위치 파악 및 수정 용이
- 👥 Team-friendly: Clear code organization | 명확한 코드 구조
⚡ Performance Comparison | 성능 비교
// ❌ Redux: Entire component re-renders
const state = useSelector((state) => state); // Everything triggers re-render
// 전체 컴포넌트 리렌더링
// ❌ Context: All consumers re-render
const { user, todos, settings } = useContext(AppContext);
// 모든 컨슈머 리렌더링
// ✅ Forma: Surgical precision
const userName = state.useValue("user.name"); // Only this
const todoCount = state.useValue("todos.length"); // Only this
const theme = state.useValue("settings.theme"); // Only this
// 수술적 정밀도Real-world impact | 실제 영향:
- 📊 50+ fields: 10-100x faster than Redux | Redux 대비 10-100배 빠름
- ⚡ Real-time forms: Smooth 60fps performance | 부드러운 60fps 성능
- 📱 Mobile: Better battery life | 배터리 수명 향상
- 🎯 Zero wasted renders: Every render is intentional | 모든 렌더링이 의도적
View Detailed Performance Guide | 성능 가이드 보기
Links | 링크
- 📦 NPM: https://www.npmjs.com/package/@ehfuse/forma
- 🐙 GitHub: https://github.com/ehfuse/forma
- 📄 License: MIT
Contact | 연락처
- Developer: 김영진 (KIM YOUNG JIN)
- Email: ehfuse@gmail.com
- GitHub: @ehfuse
Copyright (c) 2025 김영진 (KIM YOUNG JIN) - MIT License