前言
hello 大家好,我是一个菜鸟程序员,都说学习前端框架大多从 TodoList 学起,我呢,学习 react 也有一段时间了,特此做了一个 TodoList 做为自己的学习总结,顺便发个博客记录一下自己的学习,如有错漏欢迎大神在评论区指点。
环境安装
注意
第一行的 npx 不是拼写错误 —— 它是 npm 5.2+ 附带的 package 运行工具。
npx create-react-app my-app
cd my-app
删除掉新项目中 src/ 文件夹下的所有文件,并新建二个文件,index.js 和 index.css.
安装 antd,使用 UI 框架让我们的 TodoList 更加美观
npm install antd --save
分别复制以下代码到 index.js ,index.css
index.js
import React from "react";
import ReactDOM from "react-dom";
import { Button, Divider, Input, Row, Col } from "antd";
import "antd/dist/antd.css"; // or 'antd/dist/antd.less'
import "./index.css";
class List extends React.Component {
render() {
return (
<div className="list">
<Row className="list-item">
<Col span={16}>col</Col>
<Col span={4}><Button>修改</Button></Col>
<Col span={4}><Button>删除</Button></Col>
</Row>
</div>
);
}
}
class Add extends React.Component {
render() {
return (
<div className="add">
<Input
placeholder="请输入需要添加的事项"
allowClear
/>
<Button type="primary">添加</Button>
</div>
);
}
}
class TodoList extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div className="todolist">
<Divider>TodoList</Divider>
<Add />
<List />
</div>
);
}
}
// ========================================
ReactDOM.render(<TodoList />, document.getElementById("root"));
index.css
*{
margin: 0;
padding: 0;
}
html,body{
height: 100vh;
overflow: hidden;
}
.todolist{
width: 400px;
height: 630px;
margin: 100px auto;
border: 2px solid #000;
padding: 20px;
}
.list{
height: 430px;
overflow-y: scroll;
}
.list-item{
margin-top: 20px;
}
.add{
display: flex;
}
.performance{
display: flex;
justify-content: space-between;
}
.finish{
text-decoration:line-through;
text-line-through-color:red
}
启动项目,这时我们已经可以看到 TodoList 大致的样子了
npm start
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i51S1ZLM-1598491947715)(https://imgkr2.cn-bj.ufileos.com/d459b745-7625-49e0-b34d-bf091a2d0e77.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=ljjg8xj5BnxmjYFjZdJNU%252FSTX6s%253D&Expires=1598432071)]
编写添加功能
这个小案例,我采用的是所有数据都交由父组件处理,然后分发给子组件,所以我们先在父组件的 state 里面声明一个 text 和 list,text 用于存储输入框的值,list 用于存储添加的列表。
constructor(props) {
super(props);
this.state = {
list: [],
text: "",
};
}
编写输入框的 change 事件,利用一起传入的text赋值给输入框的value属性实现数据的双向绑定并通过添加事件获取text来修改list,其中我们用时间戳来当做添加数据的id,完整代码如下
TodoList
class TodoList extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [],
text: "",
};
}
// 绑定输入框的值
handleChange(e) {
e.persist();
this.setState({
text: e.target.value,
});
}
//添加
handleAdd() {
if (!this.state.text) {
alert("输入框不能为空");
return;
}
const Itme = { text: this.state.text, id: Date.now()};
this.setState({
list: [Itme, ...this.state.list],
text: "",
});
}
render() {
return (
<div className="todolist">
<Divider>TodoList</Divider>
<Add
change={(e) => this.handleChange(e)}
text={this.state.text}
addClick={() => this.handleAdd()}
/>
<List list={this.state.list}/>
</div>
);
}
}
Add
class Add extends React.Component {
render() {
return (
<div className="add">
<Input
placeholder="请输入需要添加的事项"
onChange={(e) => this.props.change(e)}
allowClear
value={this.props.text}
/>
<Button type="primary" onClick={() => this.props.addClick()}>添加</Button>
</div>
);
}
}
通过遍历父组件传过来的list生成当前列表
List
class List extends React.Component {
render() {
const list = this.props.list
return (
<div className="list">
{list.map((item) => (
<Row className="list-item" key={item.id}>
<Col span={16} >{item.text}</Col>
<Col span={4}>
<Button type="primary">修改</Button>
</Col>
<Col span={4}>
<Button type="primary" danger>删除</Button>
</Col>
</Row>
))}
</div>
);
}
}
添加修改功能
在父组件的 state 里面声明一个 AddOrUpdate 变量来存储当前是处于添加状态还是修改状态及需要修改项的id,在默认的清空下是处于添加状态,可以通过修改按钮更改为修改状态,当修改完成后还原成添加状态
TodoList
class TodoList extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [],
text: "",
AddOrUpdate: { isAdd: true },
};
}
// 绑定输入框的值
handleChange(e) {
e.persist();
this.setState({
text: e.target.value,
});
}
//添加 | 修改
handleAdd() {
if (!this.state.text) {
alert("输入框不能为空");
return;
}
if (this.state.AddOrUpdate.isAdd) {
const Itme = { text: this.state.text, id: Date.now(), isFinish: false };
this.setState({
list: [Itme, ...this.state.list],
text: "",
});
} else {
let { id } = this.state.AddOrUpdate;
let newlist = this.state.list;
newlist.map((item) => item.id === id && (item.text = this.state.text));
this.setState({
list: [...newlist],
AddOrUpdate: { isAdd: true },
text: "",
});
}
}
//修改
handleUpdate(item) {
this.setState({
AddOrUpdate: { isAdd: false, id: item.id },
text: item.text,
});
}
render() {
return (
<div className="todolist">
<Divider>TodoList</Divider>
<Add
change={(e) => this.handleChange(e)}
text={this.state.text}
addClick={() => this.handleAdd()}
AddOrUpdate={this.state.AddOrUpdate}
/>
<List
list={this.state.list}
update={(item) => this.handleUpdate(item)}
/>
</div>
);
}
}
Add
class Add extends React.Component {
render() {
return (
<div className="add">
<Input
placeholder="请输入需要添加的事项"
onChange={(e) => this.props.change(e)}
allowClear
value={this.props.text}
/>
<Button type="primary" onClick={() => this.props.addClick()}>
{this.props.AddOrUpdate.isAdd ? "添加" : "确定修改"}
</Button>
</div>
);
}
}
List
class List extends React.Component {
render() {
const list = this.props.list;
return (
<div className="list">
{list.map((item) => (
<Row className="list-item" key={item.id}>
<Col span={16}>{item.text}</Col>
<Col span={4}>
<Button type="primary" onClick={() => this.props.update(item)}>
修改
</Button>
</Col>
<Col span={4}>
<Button
type="primary"
danger
>
删除
</Button>
</Col>
</Row>
))}
</div>
);
}
}
添加删除功能
这里我是通过filter来筛除点击的列表项实现删除功能的
//删除
handleDelete(item) {
this.setState({
list: this.state.list.filter((i) => i.id !== item.id),
});
}
接下来我们来实现最后一个功能了,也就是查询功能
我的思路是这样子的,给每条数据增加一个自定义状态(完成和未完成),默认都是未完成,通过点击当前项来修改当前数据的状态,
设置三个按钮(全部,未完成,已完成),然后在父组件设置一个变量来存储这三个状态,通过分别点击这三个按钮来状态,然后把这个状态传递给列表组件(List组件),通过filter实现数据的筛选,因为我们所有的子组件的不包含state,所以我们可以优化一下都写成函数式组件
完整代码如下
import React from "react";
import ReactDOM from "react-dom";
import { Button, Divider, Input, Row, Col } from "antd";
import "antd/dist/antd.css"; // or 'antd/dist/antd.less'
import "./index.css";
function List(props) {
let list = props.list;
if(props.condition === 'finish'){
list = list.filter(item=>item.isFinish)
}
if(props.condition === 'unfinished'){
list = list.filter(item=>!item.isFinish)
}
return (
<div className="list">
{list.map((item) => (
<Row className="list-item" key={item.id}>
<Col span={16} onClick={() => props.isFinish(item)} className={item.isFinish ? 'finish': null}>
{item.text}
</Col>
<Col span={4}>
<Button type="primary" onClick={() => props.update(item)}>
修改
</Button>
</Col>
<Col span={4}>
<Button
onClick={() => props.deleteClick(item)}
type="primary"
danger
>
删除
</Button>
</Col>
</Row>
))}
</div>
);
}
function Add(props) {
return (
<div className="add">
<Input
placeholder="请输入需要添加的事项"
allowClear
onChange={(e) => props.change(e)}
value={props.text}
/>
<Button type="primary" onClick={() => props.addClick()}>
{props.AddOrUpdate.isAdd ? "添加" : "确定修改"}
</Button>
</div>
);
}
function Performance(props) {
return (
<div className="performance">
{
props.status.map(item=>(
<Button type="primary" onClick={()=>props.statusClick(item.state)} key={item.state}>{item.text}</Button>
))
}
</div>
);
}
class TodoList extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [],
text: "",
AddOrUpdate: { isAdd: true },
status:[
{
text:'全部',
state:'All'
},
{
text:'已完成',
state:'finish'
},
{
text:'未完成',
state:'unfinished'
}
],
condition:'All'
};
}
handleAdd() {
if (!this.state.text) {
alert("输入框不能为空");
return;
}
if (this.state.AddOrUpdate.isAdd) {
const Itme = { text: this.state.text, id: Date.now(),isFinish:false};
this.setState({
list: [Itme, ...this.state.list],
text: "",
});
} else {
let { id } = this.state.AddOrUpdate;
let newlist = this.state.list;
newlist.map((item) => item.id === id && (item.text = this.state.text));
this.setState({
list: [...newlist],
AddOrUpdate: { isAdd: true },
text: "",
});
}
}
handleDelete(item) {
this.setState({
list: this.state.list.filter((i) => i.id !== item.id),
});
}
handleChange(e) {
e.persist();
this.setState({
text: e.target.value,
});
}
handleUpdate(item) {
this.setState({
AddOrUpdate: { isAdd: false, id: item.id },
text: item.text,
});
}
handleIsFinish(data) {
let newlist = this.state.list;
newlist.map((item) => item.id === data.id && (item.isFinish = !item.isFinish));
this.setState({
list: [...newlist],
});
}
handleStatus(state){
this.setState({
condition:state
})
}
render() {
return (
<div className="todolist">
<Divider>TodoList</Divider>
<Add
addClick={() => this.handleAdd()}
text={this.state.text}
change={(e) => this.handleChange(e)}
AddOrUpdate={this.state.AddOrUpdate}
/>
<List
list={this.state.list}
deleteClick={(item) => this.handleDelete(item)}
update={(item) => this.handleUpdate(item)}
isFinish={(item) => this.handleIsFinish(item)}
condition={this.state.condition}
/>
<Performance status={this.state.status} statusClick={(state)=>this.handleStatus(state)}/>
</div>
);
}
}
// ========================================
ReactDOM.render(<TodoList />, document.getElementById("root"));
总结
react --TodoList 学习之旅到此结束了,希望我的学习经验能让大家有所收获,如有更好的实现方法可以在评论区留言哦!!!