diff --git a/src/strategies/index.ts b/src/strategies/index.ts
index 1253936..c6a5992 100644
--- a/src/strategies/index.ts
+++ b/src/strategies/index.ts
@@ -1,3 +1,7 @@
+import { UseReducer } from "./useReducer";
import { UseState } from "./useState";
-export const strategies = [{ name: 'useState', component: UseState }]
+export const strategies = [
+ { name: 'useState', component: UseState },
+ { name: 'useReducer', component: UseReducer },
+]
diff --git a/src/strategies/useReducer.tsx b/src/strategies/useReducer.tsx
new file mode 100644
index 0000000..d53cfd3
--- /dev/null
+++ b/src/strategies/useReducer.tsx
@@ -0,0 +1,145 @@
+import React, { useEffect, useReducer, useState } from 'react'
+import localforage from 'localforage'
+import { useAsyncValue } from 'react-router'
+
+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))
+ }
+}
+
+export function UseReducer() {
+ 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 (
+
+
+
+
+ )
+}
+
+function TodoList({
+ todos,
+ dispatch
+}: {
+ todos: Todo[]
+ dispatch: (TodoAction) => void
+}) {
+ return (
+ <>
+ {todos.map((todo) => (
+
+ ))}
+ >
+ )
+}
+
+function TodoItem({
+ todo,
+ dispatch
+}: {
+ todo: Todo
+ dispatch: (TodoAction) => void
+}) {
+ return (
+
+ )
+}
diff --git a/src/strategies/useState.tsx b/src/strategies/useState.tsx
index 51b2e04..0e7902f 100644
--- a/src/strategies/useState.tsx
+++ b/src/strategies/useState.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react'
+import React, { useEffect, useState } from 'react'
import localforage from 'localforage'
type Todo = {
@@ -12,21 +12,20 @@ export function UseState() {
const [todos, setTodos] = useState([])
const [newTodoText, setNewTodoText] = useState('')
- localforage.getItem('react-state-management/todos', (_err, value) => {
- if (value) {
- setTodos(value as Todo[]) // validation first would be better
- }
- setLoading(false)
- })
-
- function updateTodos(newTodos: Todo[]) {
- // alternative to tricky useEffect
- setLoading(true)
- setTodos(newTodos)
- localforage.setItem('react-state-management/todos', newTodos).then(() => {
+ useEffect(() => {
+ // run once when mounted
+ localforage.getItem('react-state-management/todos', (_err, value) => {
+ if (value) {
+ setTodos(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 = {
@@ -36,11 +35,11 @@ export function UseState() {
}
const newTodos = [...todos, newTodo]
setNewTodoText('')
- updateTodos(newTodos)
+ setTodos(newTodos)
}
function todoSetter(id: string, newValue?: Todo) {
- updateTodos(
+ setTodos(
todos.reduce((acc, cur) => {
if (cur.id === id) {
if (newValue === undefined) {