Skip to content

Commit f5dc84f

Browse files
author
chungheon_yi
committed
docs: to-do-list example 추가
1 parent 1a63ed3 commit f5dc84f

File tree

9 files changed

+176
-9
lines changed

9 files changed

+176
-9
lines changed

apps/core/src/models/NamespaceStore.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { deepClone } from '../utils'
12
import EventPublisher from './EventPublisher'
23
import { Listener } from './type'
34
import { createStateProxy } from './utils/createStateProxy'
@@ -12,20 +13,15 @@ export default class NamespaceStore<State extends Record<string | symbol, any>>
1213

1314
private publisher: EventPublisher<State>
1415

15-
protected deepClone(value: any) {
16-
// @ts-ignore
17-
return global.structuredClone ? structuredClone?.(value) : JSON.parse(JSON.stringify(value))
18-
}
19-
2016
constructor(initialState: State) {
21-
this.initState = this.deepClone(initialState)
17+
this.initState = deepClone(initialState)
2218

2319
this.publisher = new EventPublisher<State>()
2420
this.state = createStateProxy(initialState, this.publisher)
2521
}
2622

2723
reset() {
28-
const deepCopiedState = this.deepClone(this.initState)
24+
const deepCopiedState = deepClone(this.initState)
2925

3026
Object.keys(deepCopiedState).forEach((key) => {
3127
this.state[key as keyof State] = deepCopiedState[key]

apps/core/src/utils/deepClone.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export function deepClone(value: any) {
2+
// @ts-ignore
3+
return global.structuredClone ? structuredClone?.(value) : JSON.parse(JSON.stringify(value))
4+
}

apps/core/src/utils/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from './deepClone'
12
export * from './ProxyWrapper'

apps/docs/stories/scope/createContextScope.stories.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ const { Provider: DialogProvider, useNamespaceStores: useDialogNamespaceStore }
4242
localStore: () => new Counter(),
4343
})
4444

45-
46-
4745
const [createAlertDialogProvider, createAlertDialogScope] = createNamespaceScope('AlertDialog', [createDialogScope])
4846

4947
const { Provider: AlertDialogProvider, useNamespaceStores: useAlertDialogNamespaceStore } = createAlertDialogProvider(
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import React, { useState } from 'react'
2+
3+
import { createTodoScope, TodoProvider } from './scope'
4+
import TodoList from './ToDoList'
5+
6+
const user1Scope = createTodoScope()
7+
const user2Scope = createTodoScope()
8+
const user3Scope = createTodoScope()
9+
10+
const App = () => {
11+
const [activeUserId, setActiveUserId] = useState<'user1' | 'user2' | 'user3'>('user1')
12+
const todoScopes = {
13+
user1: user1Scope({}),
14+
user2: user2Scope({}),
15+
user3: user3Scope({}),
16+
} as const
17+
18+
const handleUserChange = (userId: 'user1' | 'user2' | 'user3') => {
19+
setActiveUserId(userId)
20+
}
21+
22+
const scope = todoScopes?.[activeUserId]?.__scopeTodoList
23+
24+
return (
25+
<div>
26+
<h1>Multi-User To-Do List</h1>
27+
<div>
28+
<button type="button" onClick={() => handleUserChange('user1')}>
29+
Switch to User 1
30+
</button>
31+
<button type="button" onClick={() => handleUserChange('user2')}>
32+
Switch to User 2
33+
</button>
34+
<button type="button" onClick={() => handleUserChange('user3')}>
35+
Switch to User 3
36+
</button>
37+
</div>
38+
<TodoProvider scope={todoScopes.user1?.__scopeTodoList}>
39+
<TodoProvider scope={todoScopes.user2?.__scopeTodoList}>
40+
<TodoProvider scope={todoScopes.user3?.__scopeTodoList}>
41+
<TodoList scope={scope} />
42+
</TodoProvider>
43+
</TodoProvider>
44+
</TodoProvider>
45+
</div>
46+
)
47+
}
48+
49+
export default App
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import App from './App'
2+
3+
/* eslint-disable max-classes-per-file */
4+
5+
const meta = {
6+
title: 'scope/to-do-list',
7+
8+
parameters: {},
9+
argTypes: {},
10+
}
11+
12+
export default meta
13+
14+
export const Example = () => {
15+
return <App />
16+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { Scope } from '@lodado/react-namespace'
2+
import React, { useState } from 'react'
3+
4+
import { useTodoNamespaceStore } from './scope'
5+
6+
interface UserTodoListProps {
7+
scope: Scope<any>
8+
}
9+
10+
const TodoList: React.FC<UserTodoListProps> = ({ scope }) => {
11+
const { user, todos, addTodo, toggleTodo, removeTodo } = useTodoNamespaceStore(
12+
(state) => ({ user: state.user, todos: state.todos }),
13+
scope,
14+
)
15+
const [newTodo, setNewTodo] = useState('')
16+
17+
const handleAddTodo = () => {
18+
if (newTodo.trim() !== '') {
19+
addTodo(newTodo.trim())
20+
setNewTodo('')
21+
}
22+
}
23+
24+
return (
25+
<div>
26+
<h2>{user} To-Do List</h2>
27+
<input type="text" value={newTodo} onChange={(e) => setNewTodo(e.target.value)} placeholder="Add a new task..." />
28+
<button type="button" onClick={handleAddTodo}>
29+
Add
30+
</button>
31+
<ul>
32+
{todos.map((todo) => (
33+
<li key={todo.id} style={{ display: 'flex', alignItems: 'center' }}>
34+
<input type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} />
35+
<span
36+
style={{
37+
textDecoration: todo.completed ? 'line-through' : 'none',
38+
marginLeft: '8px',
39+
}}
40+
>
41+
{todo.title}
42+
</span>
43+
<button type="button" onClick={() => removeTodo(todo.id)} style={{ marginLeft: 'auto', color: 'red' }}>
44+
Remove
45+
</button>
46+
</li>
47+
))}
48+
</ul>
49+
</div>
50+
)
51+
}
52+
53+
export default TodoList
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { createNamespaceScope } from '@lodado/react-namespace'
2+
3+
import TodoStore from './toDoStore'
4+
5+
export const [createTodoContext, createTodoScope] = createNamespaceScope('TodoList')
6+
7+
export const { Provider: TodoProvider, useNamespaceStores: useTodoNamespaceStore } = createTodoContext<TodoStore>(
8+
'TodoList',
9+
{
10+
localStore: () => new TodoStore(),
11+
},
12+
)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { NamespaceStore } from '@lodado/namespace-core'
2+
3+
export interface Todo {
4+
id: number
5+
title: string
6+
completed: boolean
7+
}
8+
9+
export interface TodoState {
10+
todos: Todo[]
11+
user: string
12+
}
13+
14+
let index = 0
15+
16+
export default class TodoStore extends NamespaceStore<TodoState> {
17+
constructor() {
18+
index += 1
19+
super({ user: `user${index}}`, todos: [] })
20+
}
21+
22+
addTodo(title: string) {
23+
const newTodo: Todo = {
24+
id: Date.now(),
25+
title,
26+
completed: false,
27+
}
28+
this.state.todos = [...this.state.todos, newTodo]
29+
}
30+
31+
toggleTodo(id: number) {
32+
this.state.todos = this.state.todos.map((todo) => (todo.id === id ? { ...todo, completed: !todo.completed } : todo))
33+
}
34+
35+
removeTodo(id: number) {
36+
this.state.todos = this.state.todos.filter((todo) => todo.id !== id)
37+
}
38+
}

0 commit comments

Comments
 (0)