react todo list
todolist/src/main.jsx
| import React from 'react' |
| import ReactDOM from 'react-dom/client' |
| import App from './App.jsx' |
| import './index.css' |
| |
| ReactDOM.createRoot(document.getElementById('root')).render( |
| <React.StrictMode> |
| <App /> |
| </React.StrictMode>, |
| ) |
| |
todolist/src/App.jsx
| import { useEffect, useState } from "react" |
| |
| export default function App() { |
| |
| const [curTodo, setCurTodo] = useState('') |
| |
| const [todos, setTodos] = useState(() => { |
| const localValue = localStorage.getItem("ITEMS") |
| if (localValue == null) return [] |
| return JSON.parse(localValue) |
| }) |
| |
| useEffect(() => { |
| localStorage.setItem("ITEMS", JSON.stringify(todos)) |
| }, [todos]) |
| |
| function addTodo(e) { |
| e.preventDefault() |
| if (curTodo.length === 0) return |
| setTodos(() => |
| [ |
| ...todos, |
| { |
| id: crypto.randomUUID(), |
| title: curTodo, |
| status: false |
| } |
| ] |
| ) |
| setCurTodo('') |
| } |
| |
| function toggleTodo(id, status) { |
| setTodos(() => |
| todos.map(todo => { |
| if (todo.id === id) { |
| return { ...todo, status } |
| } |
| return todo |
| }) |
| ) |
| } |
| |
| function deleteTodo(id) { |
| setTodos(() => |
| |
| todos.filter(todo => todo.id !== id) |
| ) |
| } |
| |
| |
| return ( |
| <> |
| <form onSubmit={addTodo}> |
| <input type="text" value={curTodo} onChange={e => setCurTodo(e.target.value)} /> |
| <button>Add</button> |
| </form> |
| <ul> |
| { |
| todos.map(todo => |
| <li key={todo.id}> |
| <label> |
| <input |
| type="checkbox" |
| checked={todo.status} |
| onChange={(e) => toggleTodo(todo.id, e.target.checked)} |
| /> |
| {todo.title} |
| </label> |
| <button onClick={() => deleteTodo(todo.id)}>Delete</button> |
| </li> |
| ) |
| } |
| </ul> |
| </> |
| ) |
| } |
| |
| |
| |
todolist/index.html
| <!doctype html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| <title>Vite + React</title> |
| </head> |
| <body> |
| <div id="root"></div> |
| <script type="module" src="/src/main.jsx"></script> |
| </body> |
| </html> |
| |
todolist/vite.config.js
| import { defineConfig } from 'vite' |
| import react from '@vitejs/plugin-react' |
| |
| |
| export default defineConfig({ |
| plugins: [react()], |
| }) |
| |
todolist/package.json
| { |
| "name": "todolist", |
| "private": true, |
| "version": "0.0.0", |
| "type": "module", |
| "scripts": { |
| "dev": "vite", |
| "build": "vite build", |
| "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", |
| "preview": "vite preview" |
| }, |
| "dependencies": { |
| "react": "^18.2.0", |
| "react-dom": "^18.2.0" |
| }, |
| "devDependencies": { |
| "@types/react": "^18.2.15", |
| "@types/react-dom": "^18.2.7", |
| "@vitejs/plugin-react": "^4.0.3", |
| "eslint": "^8.45.0", |
| "eslint-plugin-react": "^7.32.2", |
| "eslint-plugin-react-hooks": "^4.6.0", |
| "eslint-plugin-react-refresh": "^0.4.3", |
| "vite": "^4.4.5" |
| } |
| } |
| |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2022-09-17 nginx-nginx的文件服务器的配置
2022-09-17 python—多线程之守护线程