App.js
import { AddTask } from './utils/AddTask'
import { TaskList } from './utils/TaskList'
import { TasksProvider } from "./utils/TaskContext"
function App() {
return (
<>
<TasksProvider>
<AddTask />
<TaskList />
</TasksProvider>
</>
)
}
export default App
TaskList.js
import { useState } from "react"
import { useTasks, useTasksDispatch } from "./TaskContext"
export function TaskList() {
const tasks = useTasks()
return (
<ul>
{tasks.map(task => (
<Item task={task} key={task.id} />
))}
</ul>
)
}
export function Item({task}) {
const dispatch = useTasksDispatch()
const [isEditing, setIsEditing] = useState(false)
const [text, setText] = useState(task.text)
const [isChecked, setIsChecked] = useState(task.done)
function handleClick() {
setIsEditing(false)
dispatch({
type: "change",
task: {...task, text, done: isChecked}
})
}
return (
<li>
<label>
<input type="checkbox" checked={isChecked} onChange={e => setIsChecked(!isChecked)} />
{!isEditing ? (
<>
<span>{task.text}</span>
<button onClick={() => setIsEditing(true)}>Edit</button>
</>
) : (
<>
<input value={text} onChange={e => setText(e.target.value)} />
<button onClick={handleClick}>Save</button>
</>
)}
<button onClick={e => {
dispatch({type: "del", taskId: task.id})
}}>Delete</button>
</label>
</li>
)
}
AddTask.js
import { useState } from "react"
import { useTasksDispatch } from "./TaskContext"
export function AddTask() {
const dispatch = useTasksDispatch()
const [text, setText] = useState("")
function handleClick() {
dispatch({type: "add", text})
setText("")
}
return (
<>
<input value={text} onChange={e => setText(e.target.value)} />
<button onClick={handleClick}>Add</button>
</>
)
}
TaskContext.js
import { createContext, useContext } from "react"
import { useReducer } from "react"
const TaskContext = createContext(null)
const TaskDispatchContext = createContext(null)
const initialTasks = [
{id: 0, text: 'Visit Kafka Museum', done: true},
{id: 1, text: 'Watch a puppet show', done: false},
{id: 2, text: 'Lennon Wall pic', done: false},
]
let nextId = initialTasks.length
function tasksReducer(tasks, action) {
switch (action.type) {
case "add": {
return [
...tasks,
{
id: nextId++,
text: action.text,
done: false
}
]
}
case "change": {
return tasks.map(task => {
if (task.id === action.task.id) {
return action.task
} else {
return task
}
})
}
case "del": {
return tasks.filter(task => task.id !== action.taskId)
}
default: {
throw new Error(`位置的类型:${action.type}`)
}
}
}
export function useTasks() {
return useContext(TaskContext)
}
export function useTasksDispatch() {
return useContext(TaskDispatchContext)
}
export function TasksProvider({children}) {
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks)
return (
<TaskContext.Provider value={tasks}>
<TaskDispatchContext.Provider value={dispatch}>
{children}
</TaskDispatchContext.Provider>
</TaskContext.Provider>
)
}