diff --git a/examples/task-list/src/components/application.jsx b/examples/task-list/src/components/application.jsx new file mode 100644 index 0000000..ddda7fb --- /dev/null +++ b/examples/task-list/src/components/application.jsx @@ -0,0 +1,43 @@ +import { useEffect, useReducer } from 'react'; + +import * as api from '../api'; +import { initialState, taskReducer } from '../reducer'; + +import { CreateTask } from './create-task'; +import { Tasks } from './tasks'; + +export const Application = () => { + const [state, dispatch] = useReducer(taskReducer, initialState); + const { tasks } = state; + + useEffect(() => { + api.all().then((payload) => { + dispatch({ type: 'set-tasks', payload }); + }); + }, [dispatch]); + + const addTask = (title) => { + api.add(title).then((payload) => { + dispatch({ type: 'add-task', payload }); + }); + }; + + const updateTask = (id, updatedTask) => { + api.update(id, updatedTask).then(() => { + dispatch({ type: 'update-task', payload: { id, ...updatedTask } }); + }); + }; + + const removeTask = (id) => { + api.remove(id).then(() => { + dispatch({ type: 'remove-task', payload: id }); + }); + }; + + return ( +
+ + +
+ ); +}; diff --git a/examples/task-list/src/components/application.tsx b/examples/task-list/src/components/application.tsx deleted file mode 100644 index 0597df6..0000000 --- a/examples/task-list/src/components/application.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { CreateTask } from './create-task'; -import { TaskProvider } from '../contexts/task-context'; -import { Tasks } from './tasks'; - -export const Application = () => { - return ( - -
- console.log(title)} /> - -
-
- ); -}; diff --git a/examples/task-list/src/components/create-task.tsx b/examples/task-list/src/components/create-task.jsx similarity index 78% rename from examples/task-list/src/components/create-task.tsx rename to examples/task-list/src/components/create-task.jsx index 530368f..da2b553 100644 --- a/examples/task-list/src/components/create-task.tsx +++ b/examples/task-list/src/components/create-task.jsx @@ -1,8 +1,6 @@ import { useState } from 'react'; -import { useTaskActions } from '../contexts/task-context'; -export const CreateTask = () => { - const { addTask } = useTaskActions(); +export const CreateTask = ({ onSubmit }) => { const [title, setTitle] = useState(''); return ( @@ -11,7 +9,7 @@ export const CreateTask = () => { action="/api/tasks" onSubmit={(event) => { event.preventDefault(); - addTask(title); + onSubmit(title); setTitle(''); }} > @@ -19,7 +17,7 @@ export const CreateTask = () => { -
+
& { - date: Date | string; - title: string; }) => { if (typeof date === 'string') date = new Date(date); + return (
diff --git a/examples/task-list/src/components/task.jsx b/examples/task-list/src/components/task.jsx new file mode 100644 index 0000000..50bcc7c --- /dev/null +++ b/examples/task-list/src/components/task.jsx @@ -0,0 +1,33 @@ +import { memo } from 'react'; +import { ChevronRightCircle } from 'lucide-react'; +import { DateTime } from './date-time'; + +export const Task = memo(({ task, updateTask, removeTask }) => { + return ( +
  • +
    + + updateTask(task.id, { completed: !task.completed })} + /> +

    {task.title}

    + +
    +
    + + +
    +
  • + ); +}); diff --git a/examples/task-list/src/components/task.tsx b/examples/task-list/src/components/task.tsx deleted file mode 100644 index eeada4d..0000000 --- a/examples/task-list/src/components/task.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { memo } from 'react'; -import { ChevronRightCircle } from 'lucide-react'; -import { DateTime } from './date-time'; -import { useTaskActions } from '../contexts/task-context'; - -type TaskProps = { - task: import('../types').Task; -}; - -export const Task = memo(({ task }: TaskProps) => { - const { updateTask, removeTask } = useTaskActions(); - - return ( -
  • -
    - - updateTask(task.id, { completed: !task.completed })} - /> -

    {task.title}

    - -
    - -
  • - ); -}); diff --git a/examples/task-list/src/components/tasks.jsx b/examples/task-list/src/components/tasks.jsx new file mode 100644 index 0000000..df52eea --- /dev/null +++ b/examples/task-list/src/components/tasks.jsx @@ -0,0 +1,16 @@ +import { Task } from './task'; + +export const Tasks = ({ tasks, updateTask, removeTask }) => { + return ( +
      + {tasks.map((task) => ( + + ))} +
    + ); +}; diff --git a/examples/task-list/src/components/tasks.tsx b/examples/task-list/src/components/tasks.tsx deleted file mode 100644 index 6fbc293..0000000 --- a/examples/task-list/src/components/tasks.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Task } from './task'; -import { useTaskState } from '../contexts/task-context'; - -export const Tasks = () => { - const tasks = useTaskState(); - - return ( -
      - {tasks.map((task) => ( - - ))} -
    - ); -}; diff --git a/examples/task-list/src/contexts/task-context.tsx b/examples/task-list/src/contexts/task-context.tsx deleted file mode 100644 index 41ae02b..0000000 --- a/examples/task-list/src/contexts/task-context.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { - createContext, - useReducer, - useMemo, - useEffect, - type PropsWithChildren, - useContext, - useCallback, -} from 'react'; - -import { taskReducer, initialState } from '../reducer'; -import { bindActionCreators } from '../actions'; -import * as api from '../api'; -import type { Task, TaskContextProps } from '../types'; - -const TaskContext = createContext(undefined); - -const TaskProvider = ({ children }: PropsWithChildren) => { - const [state, dispatch] = useReducer(taskReducer, initialState); - const { setLoading, setError, ...actions } = bindActionCreators(dispatch); - - // Fetch all tasks - const getAllTasks = useCallback(async () => { - setLoading(); - try { - const tasks = await api.all(); - actions.setTasks(tasks); - } catch (error) { - setError(error, 'Failed to fetch tasks'); - } - }, [dispatch]); - - // Add a new task - const addTask = useCallback( - async (title: string) => { - setLoading(); - try { - const task = await api.add(title); - actions.addTask(task); - } catch (error) { - setError(error, 'Failed to add task'); - } - }, - [dispatch], - ); - - // Update a task - const updateTask = useCallback( - async (id: string, updatedTask: Partial) => { - setLoading(); - - try { - await api.update(id, updatedTask); - actions.updateTask(id, updatedTask); - } catch (error) { - setError(error, 'Failed to update task'); - } - }, - [dispatch], - ); - - // Delete a task - const removeTask = useCallback( - async (id: string) => { - setLoading(); - try { - await api.remove(id); - actions.removeTask(id); - } catch (error) { - setError(error, 'Failed to delete task'); - } - }, - [dispatch], - ); - - useEffect(() => { - getAllTasks(); - }, []); - - return ( - - {children} - - ); -}; - -const useTaskState = () => { - const context = useContext(TaskContext); - - if (!context) { - throw new Error('useTaskContext must be used within a TaskProvider'); - } - - return context.tasks; -}; - -export const useTaskActions = () => { - const context = useContext(TaskContext); - - if (!context) { - throw new Error('useTaskContext must be used within a TaskProvider'); - } - - const actions = useMemo( - () => ({ - addTask: context.addTask, - updateTask: context.updateTask, - removeTask: context.removeTask, - }), - [context.addTask, context.updateTask, context.removeTask], - ); - - return actions; -}; - -export { TaskContext, TaskProvider, useTaskState }; diff --git a/examples/task-list/src/index.tsx b/examples/task-list/src/index.jsx similarity index 78% rename from examples/task-list/src/index.tsx rename to examples/task-list/src/index.jsx index baf1ffe..e9d3519 100644 --- a/examples/task-list/src/index.tsx +++ b/examples/task-list/src/index.jsx @@ -2,7 +2,7 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { Application } from './components/application'; -createRoot(document.getElementById('root')!).render( +createRoot(document.getElementById('root')).render( , diff --git a/examples/task-list/src/types.ts b/examples/task-list/src/types.ts index 96ebb5a..6c8139a 100644 --- a/examples/task-list/src/types.ts +++ b/examples/task-list/src/types.ts @@ -8,15 +8,6 @@ export type Task = { export type TaskData = Partial>; -export interface TaskContextProps { - tasks: Task[]; - loading: boolean; - error: string | null; - addTask: (title: string) => void; - updateTask: (id: string, updatedTask: Partial>) => void; - removeTask: (id: string) => void; -} - export type TaskState = { tasks: Task[]; loading: boolean;