TodoList 案例
App.jsx
jsx
import React, { Component } from 'react'
import Header from './components/Header'
import List from './components/List'
import Footer from './components/Footer'
import './App.css'
export default class App extends Component {
state = {
todos: [
{ id: '001', name: '吃饭', done: true },
{ id: '002', name: '睡觉', done: true },
{ id: '003', name: '打代码', done: false },
{ id: '004', name: '逛街', done: false }
]
}
addTodo = (todoObj) => {
const { todos } = this.state
this.setState({ todos: [todoObj, ...todos] })
}
updateTodo = (id, done) => {
const { todos } = this.state
const newTodos = todos.map(todo => todo.id === id ? { ...todo, done } : todo)
this.setState({ todos: newTodos })
}
deleteTodo = (id) => {
const { todos } = this.state
this.setState({ todos: todos.filter(todo => todo.id !== id) })
}
checkAllTodo = (done) => {
const { todos } = this.state
this.setState({ todos: todos.map(todo => ({ ...todo, done })) })
}
clearAllDone = () => {
const { todos } = this.state
this.setState({ todos: todos.filter(todo => !todo.done) })
}
render() {
const { todos } = this.state
return (
<div className="todo-container">
<div className="todo-wrap">
<Header addTodo={this.addTodo} />
<List todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo} />
<Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone} />
</div>
</div>
)
}
}import React, { Component } from 'react'
import Header from './components/Header'
import List from './components/List'
import Footer from './components/Footer'
import './App.css'
export default class App extends Component {
state = {
todos: [
{ id: '001', name: '吃饭', done: true },
{ id: '002', name: '睡觉', done: true },
{ id: '003', name: '打代码', done: false },
{ id: '004', name: '逛街', done: false }
]
}
addTodo = (todoObj) => {
const { todos } = this.state
this.setState({ todos: [todoObj, ...todos] })
}
updateTodo = (id, done) => {
const { todos } = this.state
const newTodos = todos.map(todo => todo.id === id ? { ...todo, done } : todo)
this.setState({ todos: newTodos })
}
deleteTodo = (id) => {
const { todos } = this.state
this.setState({ todos: todos.filter(todo => todo.id !== id) })
}
checkAllTodo = (done) => {
const { todos } = this.state
this.setState({ todos: todos.map(todo => ({ ...todo, done })) })
}
clearAllDone = () => {
const { todos } = this.state
this.setState({ todos: todos.filter(todo => !todo.done) })
}
render() {
const { todos } = this.state
return (
<div className="todo-container">
<div className="todo-wrap">
<Header addTodo={this.addTodo} />
<List todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo} />
<Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone} />
</div>
</div>
)
}
}Header
jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { nanoid } from 'nanoid'
export default class Header extends Component {
static propTypes = {
addTodo: PropTypes.func.isRequired
}
handleKeyUp = (event) => {
const { keyCode, target } = event
if (keyCode !== 13) return
if (target.value.trim() === '') {
alert('输入不能为空')
return
}
const todoObj = { id: nanoid(), name: target.value, done: false }
this.props.addTodo(todoObj)
target.value = ''
}
render() {
return (
<div className="todo-header">
<input
onKeyUp={this.handleKeyUp}
type="text"
placeholder="请输入你的任务名称,按回车键确认"
/>
</div>
)
}
}import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { nanoid } from 'nanoid'
export default class Header extends Component {
static propTypes = {
addTodo: PropTypes.func.isRequired
}
handleKeyUp = (event) => {
const { keyCode, target } = event
if (keyCode !== 13) return
if (target.value.trim() === '') {
alert('输入不能为空')
return
}
const todoObj = { id: nanoid(), name: target.value, done: false }
this.props.addTodo(todoObj)
target.value = ''
}
render() {
return (
<div className="todo-header">
<input
onKeyUp={this.handleKeyUp}
type="text"
placeholder="请输入你的任务名称,按回车键确认"
/>
</div>
)
}
}Footer
jsx
import React, { Component } from 'react'
export default class Footer extends Component {
handleCheckAll = (event) => {
this.props.checkAllTodo(event.target.checked)
}
handleClearAllDone = () => {
this.props.clearAllDone()
}
render() {
const { todos } = this.props
const doneCount = todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0)
const total = todos.length
return (
<div className="todo-footer">
<label>
<input
type="checkbox"
onChange={this.handleCheckAll}
checked={doneCount === total && total !== 0}
/>
</label>
<span>
<span>已完成{doneCount}</span> / 全部{total}
</span>
<button onClick={this.handleClearAllDone} className="btn btn-danger">
清除已完成任务
</button>
</div>
)
}
}import React, { Component } from 'react'
export default class Footer extends Component {
handleCheckAll = (event) => {
this.props.checkAllTodo(event.target.checked)
}
handleClearAllDone = () => {
this.props.clearAllDone()
}
render() {
const { todos } = this.props
const doneCount = todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0)
const total = todos.length
return (
<div className="todo-footer">
<label>
<input
type="checkbox"
onChange={this.handleCheckAll}
checked={doneCount === total && total !== 0}
/>
</label>
<span>
<span>已完成{doneCount}</span> / 全部{total}
</span>
<button onClick={this.handleClearAllDone} className="btn btn-danger">
清除已完成任务
</button>
</div>
)
}
}Item
jsx
import React, { Component } from 'react'
export default class Item extends Component {
state = { mouse: false }
handleMouse = (flag) => () => this.setState({ mouse: flag })
handleCheck = (id) => (event) => {
this.props.updateTodo(id, event.target.checked)
}
handleDelete = (id) => {
if (window.confirm('确定删除吗?')) {
this.props.deleteTodo(id)
}
}
render() {
const { id, name, done } = this.props
const { mouse } = this.state
return (
<li
style={{ backgroundColor: mouse ? '#ddd' : 'white' }}
onMouseEnter={this.handleMouse(true)}
onMouseLeave={this.handleMouse(false)}
>
<label>
<input type="checkbox" checked={done} onChange={this.handleCheck(id)} />
<span>{name}</span>
</label>
<button
onClick={() => this.handleDelete(id)}
className="btn btn-danger"
style={{ display: mouse ? 'block' : 'none' }}
>
删除
</button>
</li>
)
}
}import React, { Component } from 'react'
export default class Item extends Component {
state = { mouse: false }
handleMouse = (flag) => () => this.setState({ mouse: flag })
handleCheck = (id) => (event) => {
this.props.updateTodo(id, event.target.checked)
}
handleDelete = (id) => {
if (window.confirm('确定删除吗?')) {
this.props.deleteTodo(id)
}
}
render() {
const { id, name, done } = this.props
const { mouse } = this.state
return (
<li
style={{ backgroundColor: mouse ? '#ddd' : 'white' }}
onMouseEnter={this.handleMouse(true)}
onMouseLeave={this.handleMouse(false)}
>
<label>
<input type="checkbox" checked={done} onChange={this.handleCheck(id)} />
<span>{name}</span>
</label>
<button
onClick={() => this.handleDelete(id)}
className="btn btn-danger"
style={{ display: mouse ? 'block' : 'none' }}
>
删除
</button>
</li>
)
}
}List
jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item'
export default class List extends Component {
static propTypes = {
todos: PropTypes.array.isRequired,
updateTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired
}
render() {
const { todos, updateTodo, deleteTodo } = this.props
return (
<ul className="todo-main">
{todos.map(todo => (
<Item key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo} />
))}
</ul>
)
}
}import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item'
export default class List extends Component {
static propTypes = {
todos: PropTypes.array.isRequired,
updateTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired
}
render() {
const { todos, updateTodo, deleteTodo } = this.props
return (
<ul className="todo-main">
{todos.map(todo => (
<Item key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo} />
))}
</ul>
)
}
}
Cao Note