react 脚手架 todos 练手小项目分享
注意红框中的文件,其中 01_脚手架自带文件 和 02_x 不用理会,忽略就好
// App.js
import React, { Component } from 'react'
import Header from './components/Header'
import Footer from './components/Footer'
import List from './components/List'
export default class App extends Component {
constructor(props){
super(props);
this.state = {
todos:[
{
id:"001",
todo:"睡觉",
done:true
},
{
id:"002",
todo:"吃饭",
done:true
},
{
id:"003",
todo:"看书",
done:false
}
]
}
}
updateTodos = () => {
return (todoObj) => {
const todos = [todoObj,...this.state.todos];
this.setState({todos});
}
}
handleChange = (id,done) => {
const {todos} = this.state;
const newTodos = todos.map(todo => {
if(todo.id === id) return {...todo,done:done}
else return todo
})
this.setState({todos:newTodos})
}
handleDelete = (id) => {
const {todos} = this.state;
const newTodos = todos.filter((todo) => {
return todo.id !== id;
})
this.setState({todos:newTodos});
}
handleCheckedAll = (done) => {
const {todos} = this.state;
const newTodos = todos.map(todo => {
return {...todo,done}
})
this.setState({todos:newTodos})
}
handleDeleteAll = () => {
const {todos} = this.state;
const newTodos = todos.filter(todo => {
return todo.done === false;
})
this.setState({todos:newTodos})
}
render() {
const {todos} = this.state;
return (
<div className="container">
<Header updateTodos={this.updateTodos()}/>
<List todos={todos} handleChange = {this.handleChange} handleDelete = {this.handleDelete}/>
<Footer todos={todos} handleCheckedAll = {this.handleCheckedAll} handleDeleteAll = {this.handleDeleteAll}/>
</div>
)
}
}
复制代码
// Header.jsx
import React, { Component } from 'react'
import {nanoid} from 'nanoid'
export default class Header extends Component {
addItem = (event) => {
let {updateTodos} = this.props;
let todoObj = {
id:nanoid(),
todo:event.target.value,
done:false
}
if(event.keyCode === 13){
updateTodos(todoObj);
event.target.value = "";
}
}
render() {
return (
<div className="header">
<input type="text" placeholder="请输入内容,按回车键确认" onKeyUp={this.addItem}/>
</div>
)
}
}
复制代码
// List.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item'
export default class List extends Component {
static ropTypes = {
handleChange:PropTypes.func.isRequired,
todos:PropTypes.array.isRequired
}
render() {
const {todos,handleChange,handleDelete} = this.props;
return (
<ul className="list-container">
{todos.map(todo=>{
return <Item {...todo} key={todo.id} handleChange={handleChange} handleDelete = {handleDelete}/>
})}
</ul>
)
}
}
复制代码
// Item.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class Item extends Component {
static propTypes = {
handleChange:PropTypes.func.isRequired
}
deleteItem = (id) => {
console.log("被删除的id是",id);
if(window.confirm("确定删除吗?")){
this.props.handleDelete(id);
}
}
handleChange = (id) => {
const {handleChange} = this.props;
return (event) => {
handleChange(id,event.target.checked);
}
}
render() {
const {id,todo,done} = this.props;
return (
<li className="list-item">
<input type="checkbox" checked={done} onChange={this.handleChange(id)} />
<span>{todo}</span>
<button onClick={()=>{this.deleteItem(id)}}>删除</button> {/* 这里没有使用高阶函数,就直接写成了这样的 */}
</li>
)
}
}
复制代码
// Footer.jsx
import React, { Component } from 'react'
export default class Footer extends Component {
deleteAll = ()=>{
this.props.handleDeleteAll();
}
checkedAll = (event) => {
this.props.handleCheckedAll(event.target.checked);
}
render() {
const {todos} = this.props;
const total = todos.length;
const doneCount = todos.reduce((pre,current)=>{
return pre + (current.done === true ? 1 : 0);
},0)
return (
<div className="footer">
<input type="checkbox" checked={doneCount === total && total !== 0 ? true:false} onChange={this.checkedAll}/>
<span>{doneCount}完成/全部{total}</span>
<button onClick={this.deleteAll}>清除已完成项目</button>
</div>
)
}
}
复制代码
最终的成品
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END