Introduction
- Here are some ways to store state in a React Application.
+
+ This repo has a simple ToDo app mostly using React's useState
hook.
+
+
+ We will rewrite this app with useReducer
, Redux
, useContext
, and
+ something new, Preact signal
s.
+
)
}
diff --git a/src/strategies/index.ts b/src/strategies/index.ts
index b415bd6..90fe92c 100644
--- a/src/strategies/index.ts
+++ b/src/strategies/index.ts
@@ -1,9 +1,11 @@
-import { UseReducer } from "./useReducer";
-import { UseSignal } from "./useSignal";
import { UseState } from "./useState";
+import { UseReducer } from "./useReducer";
+import { UseContext } from "./useContext";
+import { UseSignal } from "./useSignal";
export const strategies = [
{ name: 'useState', component: UseState },
{ name: 'useReducer', component: UseReducer },
+ { name: 'useContext', component: UseContext },
{ name: 'useSignal', component: UseSignal },
]
diff --git a/src/strategies/useContext.tsx b/src/strategies/useContext.tsx
new file mode 100644
index 0000000..79bdc99
--- /dev/null
+++ b/src/strategies/useContext.tsx
@@ -0,0 +1,148 @@
+import React, { useContext, useEffect, useReducer, useState } from 'react'
+import localforage from 'localforage'
+
+type Todo = {
+ id: string
+ text: string
+ status: 'incomplete' | 'complete'
+}
+
+type TodoAction =
+ | {
+ type: 'delete'
+ value: string
+ }
+ | {
+ type: 'add'
+ value: Todo
+ }
+ | {
+ type: 'replace'
+ value: Todo[]
+ }
+ | {
+ type: 'update'
+ value: Todo
+ }
+const reducer = (state: Todo[], action: TodoAction) => {
+ const { type, value } = action
+ switch (type) {
+ case 'delete':
+ return state.filter((todo) => todo.id !== value)
+ case 'add':
+ return state.concat([value])
+ case 'replace':
+ return value
+ case 'update':
+ return state.map((todo) => (todo.id === value.id ? value : todo))
+ }
+}
+
+const TodoContext = React.createContext({
+ todos: [] as Todo[],
+ dispatchTodoAction: (TodoAction) => {}
+})
+
+export function UseContext() {
+ const [isLoading, setLoading] = useState(true)
+ const [todos, dispatchTodoAction] = useReducer(reducer, [])
+ const [newTodoText, setNewTodoText] = useState('')
+
+ useEffect(() => {
+ // run once when mounted
+ localforage.getItem('react-state-management/todos', (_err, value) => {
+ if (value) {
+ dispatchTodoAction({ type: 'replace', value: value as Todo[] }) // validation first would be better
+ }
+ setLoading(false)
+ })
+ }, [])
+
+ useEffect(() => {
+ // keep local db up to date
+ localforage.setItem('react-state-management/todos', todos)
+ }, [todos])
+
+ function addTodo() {
+ const newTodo = {
+ id: crypto.randomUUID(),
+ text: newTodoText,
+ status: 'incomplete' as const
+ }
+ dispatchTodoAction({
+ type: 'add',
+ value: newTodo
+ })
+ setNewTodoText('')
+ }
+
+ return (
+