Skip to content

Commit 48e00b9

Browse files
committed
feat: change useContextQuery interface & export store method
feat: add useContextMultiQuery method feat: remove init props feat: remove multiQuery & change useContextQuery interface & export store method refactor: remove return feat: change Readmefile fix: type bug feat: change readme file
1 parent 293bd93 commit 48e00b9

File tree

9 files changed

+473
-226
lines changed

9 files changed

+473
-226
lines changed

README.ko.md

Lines changed: 166 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -64,93 +64,216 @@ pnpm add @context-query/react
6464
### 1. Context Query Provider 생성
6565

6666
```tsx
67-
// CounterContextQueryProvider.tsx
67+
// UserContextQueryProvider.tsx
6868
import { createContextQuery } from "@context-query/react";
6969

70+
interface UserData {
71+
name: string;
72+
email: string;
73+
preferences: {
74+
theme: "light" | "dark";
75+
notifications: boolean;
76+
};
77+
}
78+
7079
export const {
71-
Provider: CounterQueryProvider,
72-
useContextQuery: useCounterQuery,
73-
} = createContextQuery<{ count1: number; count2: number }>();
80+
Provider: UserQueryProvider,
81+
useContextQuery: useUserQuery,
82+
updateState: updateUserState,
83+
setState: setUserState,
84+
} = createContextQuery<UserData>({
85+
name: "",
86+
email: "",
87+
preferences: {
88+
theme: "light",
89+
notifications: true,
90+
},
91+
});
7492
```
7593

76-
### 2. Provider로 컴포넌트 트리 감싸기
94+
### 2. Provider로 컴포넌트 트리 감싸기 및 상태 초기화
7795

7896
```tsx
79-
// ParentComponent.tsx
80-
import { CounterQueryProvider } from "./CounterContextQueryProvider";
97+
// UserProfilePage.tsx
98+
import { UserQueryProvider, updateUserState } from "./UserContextQueryProvider";
99+
100+
async function fetchUserData(userId: string) {
101+
const response = await fetch(`/api/users/${userId}`);
102+
return response.json();
103+
}
104+
105+
function UserProfilePage({ userId }: { userId: string }) {
106+
useEffect(() => {
107+
// 외부 데이터로 상태 초기화
108+
const loadUserData = async () => {
109+
const userData = await fetchUserData(userId);
110+
updateUserState(userData); // 가져온 데이터로 전체 상태 업데이트
111+
};
112+
loadUserData();
113+
}, [userId]);
81114

82-
function ParentComponent() {
83115
return (
84-
<CounterQueryProvider initialState={count1: 0, count2: 0}>
85-
<ChildComponentA /> {/* count1이 변경될 때만 리렌더링 */}
86-
<ChildComponentB /> {/* count2가 변경될 때만 리렌더링 */}
87-
</CounterQueryProvider>
116+
<UserQueryProvider>
117+
<div className="user-profile">
118+
<UserInfoForm />
119+
<UserPreferencesForm />
120+
<SaveButton />
121+
</div>
122+
</UserQueryProvider>
88123
);
89124
}
90125
```
91126

92127
### 3. 컴포넌트에서 상태 사용하기
93128

94129
```tsx
95-
// ChildComponentA.tsx
96-
import { useCounterQuery } from "./CounterContextQueryProvider";
97-
98-
function ChildComponentA() {
99-
const [count, setCount] = useCounterQuery("count1");
130+
// UserInfoForm.tsx
131+
import { useUserQuery } from "./UserContextQueryProvider";
100132

101-
console.log("ChildComponentA 렌더링"); // count1이 변경될 때만 로그가 출력됩니다
102-
103-
const increment = () => {
104-
setCount(count + 1);
105-
};
133+
function UserInfoForm() {
134+
// 사용자 정보 필드만 구독
135+
const [state, setState] = useUserQuery(["name", "email"]);
106136

107137
return (
108-
<div>
109-
<h2>카운터 A: {count}</h2>
110-
<button onClick={increment}>+</button>
138+
<div className="user-info">
139+
<h3>기본 정보</h3>
140+
<div>
141+
<label>이름:</label>
142+
<input
143+
value={state.name}
144+
onChange={(e) =>
145+
setState((prev) => ({ ...prev, name: e.target.value }))
146+
}
147+
/>
148+
</div>
149+
<div>
150+
<label>이메일:</label>
151+
<input
152+
value={state.email}
153+
onChange={(e) =>
154+
setState((prev) => ({ ...prev, email: e.target.value }))
155+
}
156+
/>
157+
</div>
111158
</div>
112159
);
113160
}
114161

115-
// ChildComponentB.tsx
116-
import { useCounterQuery } from "./CounterContextQueryProvider";
117-
118-
function ChildComponentB() {
119-
const [count, setCount] = useCounterQuery("count2");
120-
121-
console.log("ChildComponentB 렌더링"); // count1이 변경될 때는 로그가 출력되지 않고, count2가 변경될 때만 출력됩니다
162+
// UserPreferencesForm.tsx
163+
import { useUserQuery } from "./UserContextQueryProvider";
164+
165+
function UserPreferencesForm() {
166+
// preferences만 구독
167+
const [state, setState] = useUserQuery(["preferences"]);
168+
169+
const toggleTheme = () => {
170+
setState((prev) => ({
171+
...prev,
172+
preferences: {
173+
...prev.preferences,
174+
theme: prev.preferences.theme === "light" ? "dark" : "light",
175+
},
176+
}));
177+
};
122178

123-
const increment = () => {
124-
setCount(count + 1);
179+
const toggleNotifications = () => {
180+
setState((prev) => ({
181+
...prev,
182+
preferences: {
183+
...prev.preferences,
184+
notifications: !prev.preferences.notifications,
185+
},
186+
}));
125187
};
126188

127189
return (
128-
<div>
129-
<h2>카운터 B: {count}</h2>
130-
<button onClick={increment}>+</button>
190+
<div className="user-preferences">
191+
<h3>사용자 설정</h3>
192+
<div>
193+
<label>테마: {state.preferences.theme}</label>
194+
<button onClick={toggleTheme}>테마 변경</button>
195+
</div>
196+
<div>
197+
<label>
198+
<input
199+
type="checkbox"
200+
checked={state.preferences.notifications}
201+
onChange={toggleNotifications}
202+
/>
203+
알림 활성화
204+
</label>
205+
</div>
131206
</div>
132207
);
133208
}
209+
210+
// SaveButton.tsx
211+
import { useUserQuery, updateUserState } from "./UserContextQueryProvider";
212+
213+
function SaveButton() {
214+
// 저장을 위해 모든 사용자 데이터 가져오기
215+
const [userData] = useUserQuery(["name", "email", "preferences"]);
216+
217+
const handleSave = async () => {
218+
try {
219+
const response = await fetch("/api/users/update", {
220+
method: "POST",
221+
body: JSON.stringify(userData),
222+
});
223+
const updatedUser = await response.json();
224+
225+
// 서버 응답으로 전체 상태 업데이트
226+
updateUserState(updatedUser);
227+
} catch (error) {
228+
console.error("사용자 데이터 저장 실패:", error);
229+
}
230+
};
231+
232+
return <button onClick={handleSave}>변경사항 저장</button>;
233+
}
134234
```
135235

236+
이 예시는 다음을 보여줍니다:
237+
238+
1. 사용자 정보와 환경설정을 별도의 컴포넌트로 분리하여 관심사를 분리
239+
2. 각 컴포넌트는 필요한 상태만 구독하여 리렌더링을 최적화
240+
3. 컴포넌트들이 독립적으로 자신의 관련 상태를 업데이트
241+
136242
## 고급 사용법
137243

138-
### 함수 업데이트
244+
### 함수형 업데이트
139245

140-
React의 `useState`와 유사하게 상태 설정자에 함수를 전달할 수 있습니다:
246+
React의 `useState`와 유사하게, 상태 설정자에 함수를 전달할 수 있습니다:
141247

142248
```tsx
143-
const [count, setCount] = useCounterQuery("count1");
249+
const [count, setCount] = useCounterQuery(["count1"]);
144250

145251
// 이전 상태를 기반으로 업데이트
146252
const increment = () => {
147253
setCount((prevCount) => prevCount + 1);
148254
};
255+
// ...
149256
```
150257

151-
### 다중 Provider
258+
### 다중 상태 업데이트
152259

153-
다른 컴포넌트 서브트리를 위해 여러 Provider를 사용할 수 있습니다:
260+
updateState 함수를 사용하여 여러 상태를 한 번에 업데이트할 수 있습니다:
261+
262+
```tsx
263+
import { updateCounterState } from "./CounterContextQueryProvider";
264+
265+
// 여러 상태를 한 번에 업데이트
266+
const resetCounters = () => {
267+
updateCounterState({
268+
count1: 0,
269+
count2: 0,
270+
});
271+
};
272+
```
273+
274+
### 다중 프로바이더
275+
276+
서로 다른 컴포넌트 트리에 대해 여러 프로바이더를 사용할 수 있습니다:
154277

155278
```tsx
156279
function App() {
@@ -174,7 +297,7 @@ function App() {
174297

175298
- `@context-query/core`: 핵심 기능 및 상태 관리
176299
- `@context-query/react`: React 바인딩 및 훅
177-
- `playground`: 라이브러리를 보여주는 데모 애플리케이션
300+
- `playground`: 라이브러리 사용 예제 애플리케이션
178301

179302
## 개발
180303

@@ -195,9 +318,6 @@ pnpm install
195318

196319
# 모든 패키지 빌드
197320
pnpm build
198-
199-
# 플레이그라운드 데모 실행
200-
pnpm playground
201321
```
202322

203323
## 릴리즈 워크플로우

0 commit comments

Comments
 (0)