Skip to content

Commit

Permalink
modulize the TodoApp
Browse files Browse the repository at this point in the history
  • Loading branch information
ysmood committed Oct 10, 2024
1 parent a5220ef commit ba302f7
Show file tree
Hide file tree
Showing 16 changed files with 274 additions and 244 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ An elegant state management solution for React.
- **Non-opinionated**: Like useState, only one core function, others are built on top of it.
- **Type safe**: The state is type safe and the return value is intuitive.
- **Global**: The state is global, you can access it anywhere.
- **Scalable**: Supports selector to avoid unnecessary re-render.
- **Scalable**: Naturally scale large state into multiple modules and files without performance degradation.
- **Tiny**: Less than [0.3KB](https://bundlephobia.com/package/create-global-state).

## Documentation
Expand Down Expand Up @@ -44,4 +44,5 @@ Its implementation is not type safe and the return value is not intuitive. It's

> Why not [zustand](https://github.com/pmndrs/zustand)?
The typescript support is not good enough, the API is not intuitive. `create-global-state` is more like `useState` which aligns with the react API style. Check the [comparison](https://github.com/ysmood/create-global-state/issues/1).
The typescript support is not good enough, the API is not intuitive. `create-global-state` is more like `useState` which aligns with the react API style. Check the [comparison](https://github.com/ysmood/create-global-state/issues/1). Zustand [Slices Pattern](https://zustand.docs.pmnd.rs/guides/slices-pattern) can cause naming conflict issues.
`create-global-state` can naturally scale states by modules and files.
35 changes: 35 additions & 0 deletions examples/TodoApp/Actions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Filter from "./Filter";
import { addTodo, clearCompleted } from "./todos/actions";
import { useZeroDone } from "./todos";
import ToggleAll from "./ToggleAll";

export default function Actions() {
return (
<div className="flex gap-1">
<ToggleAll />
<Filter />
<AddTodo />
<ClearCompleted />
</div>
);
}

function AddTodo() {
return (
<button onClick={addTodo} title="Add new todo">
+
</button>
);
}

function ClearCompleted() {
return (
<button
onClick={clearCompleted}
disabled={useZeroDone()}
title="Delete all completed todos"
>
✂️
</button>
);
}
12 changes: 12 additions & 0 deletions examples/TodoApp/Filter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { filters, setFilter } from "./todos/filter";

// The component to filter the todos.
export default function Filter() {
return (
<select onChange={(e) => setFilter(e.target.value)}>
{filters.map((f) => (
<option key={f}>{f}</option>
))}
</select>
);
}
5 changes: 5 additions & 0 deletions examples/TodoApp/Title.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { useLeftCount } from "./todos";

export default function Title() {
return <h3>Todo App ({useLeftCount()} todos left)</h3>;
}
24 changes: 24 additions & 0 deletions examples/TodoApp/TodoItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { delTodo, toggleTodo, updateTodo, useTodo } from "./todos";

// The component to display a todo.
export default function TodoItem({ id }: { id: number }) {
const { done, text } = useTodo(id);

return (
<div className="flex gap-1 my-1">
<input type="checkbox" checked={done} onChange={() => toggleTodo(id)} />

<input
placeholder="Input text here"
value={text}
onChange={(e) => updateTodo(id, e.target.value)}
disabled={done}
autoFocus
/>

<button onClick={() => delTodo(id)} title="Delete current todo">
</button>
</div>
);
}
13 changes: 13 additions & 0 deletions examples/TodoApp/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useTodoIds } from "./todos";
import TodoItem from "./TodoItem";

// The component to display all filtered todos.
export default function Todos() {
return (
<>
{useTodoIds().map((id) => {
return <TodoItem key={id} id={id} />;
})}
</>
);
}
14 changes: 14 additions & 0 deletions examples/TodoApp/ToggleAll.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { toggleAll, useToggleAll } from "./todos/actions";
import { useZeroCount } from "./todos";

// The component to toggle all todos.
export default function ToggleAll() {
return (
<input
type="checkbox"
checked={useToggleAll()}
onChange={toggleAll}
disabled={useZeroCount()}
/>
);
}
94 changes: 6 additions & 88 deletions examples/TodoApp/index.tsx
Original file line number Diff line number Diff line change
@@ -1,95 +1,13 @@
import {
useList,
useTodo,
delTodo,
toggleTodo,
updateTodo,
addTodo,
clearCompleted,
filters,
setFilter,
toggleAll,
useCount,
useToggleAll,
} from "./store";
import Actions from "./Actions";
import Title from "./Title";
import TodoList from "./TodoList";

export default function TodoApp() {
return (
<div>
<h3>Todo App ({useCount(false)} todos left)</h3>
<div className="flex gap-1">
<ToggleAll />
<Filter />
<button onClick={addTodo} title="Add new todo">
+
</button>
<button
onClick={clearCompleted}
disabled={useCount(true) === 0}
title="Delete all completed todos"
>
✂️
</button>
</div>

<TodoList />
</div>
);
}

// The component to toggle all todos.
function ToggleAll() {
return (
<input
type="checkbox"
checked={useToggleAll()}
onChange={toggleAll}
disabled={useList().length === 0}
/>
);
}

// The component to filter the todos.
function Filter() {
return (
<select onChange={(e) => setFilter(e.target.value)}>
{filters.map((f) => (
<option key={f}>{f}</option>
))}
</select>
);
}

// The component to display all filtered todos.
function TodoList() {
return (
<>
{useList().map((id) => {
return <TodoItem key={id} id={id} />;
})}
<Title />
<Actions />
<TodoList />
</>
);
}

// The component to display a todo.
function TodoItem({ id }: { id: number }) {
const { done, text } = useTodo(id);

return (
<div className="flex gap-1 my-1">
<input type="checkbox" checked={done} onChange={() => toggleTodo(id)} />

<input
placeholder="Input text here"
value={text}
onChange={(e) => updateTodo(id, e.target.value)}
disabled={done}
autoFocus
/>

<button onClick={() => delTodo(id)} title="Delete current todo">
</button>
</div>
);
}
136 changes: 0 additions & 136 deletions examples/TodoApp/store.ts

This file was deleted.

Loading

0 comments on commit ba302f7

Please sign in to comment.