React简单TODO示例
一、环境信息
- NodeJS:v12.16.1
- Yarn:1.22.4
- create-react-app:3.4.1
二、创建项目
使用React官方脚手架创建项目:
create-react-app react-simple-todo
cd react-simple-todo
yarn start
浏览器出现以下画面,项目生成成功。
三、Todo List
使用下面的命令添加路由依赖:
yarn add react-router-dom antd
src目录下增加todo文件夹,新在todo下新建文件List.jsx,内容如下:
import React from 'react';
import { Table } from 'antd';
const columns = [{
title: '标题',
dataIndex: 'title',
}, {
title: '状态',
dataIndex: 'status',
}];
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [{
id: 1,
title: 'React简单示例演示任务',
status: '进行中',
}, {
id: 2,
title: '博客更新',
status: '未开始',
}]
}
}
render() {
return (
<Table dataSource={this.state.list} columns={columns} rowKey="id" />
);
}
};
export default List;
调整index.js,增加路由,最终内容如下:
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import './index.css';
import App from './App';
import Todo from './todo/List';
ReactDOM.render(
<Router>
<Route path="/" component={App} exact />
<Route path="/todo" component={Todo} />
</Router>,
document.getElementById('root')
);
此时在浏览器中输入()[http://localhost:3000/todo],可以访问todoList,但antd的没有样式,如下图:
执行下面的命令,将配置暴露出来:
yarn run eject
安装插件:
yarn add babel-plugin-import --save-dev
在package.json的babel节点下增加plugins配置,使其像下面这样:
"babel": {
"presets": [
"react-app"
],
"plugins": [
["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
]
}
服务停掉重启一次,然后界面刷新后antd样式可以正常,如下:
三、Todo Edit
接下来增加创建、修改、删除TODO的功能,首先增加Edit.jsx,用于实现编辑功能。
import React from 'react';
import { Modal, Form, Input, Select } from 'antd';
import STATUS from './status';
const Edit = ({ children, onOk, record }) => {
const [form] = Form.useForm();
const [visible, setVisible] = React.useState(false);
React.useEffect(() => {
if (visible) {
form.resetFields();
form.setFieldsValue(record);
}
}, [visible, form, record]);
const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 14 },
};
function showHandler(e) {
if (e) e.stopPropagation();
setVisible(true);
}
function hideHandler() {
setVisible(false);
}
async function okHandler () {
try {
const values = await form.validateFields();
console.log('Success: ', values);
hideHandler();
onOk(values);
} catch (errorInfo) {
console.log('Failed: ', errorInfo);
}
}
return (
<span>
<span onClick={showHandler}>
{ children }
</span>
<Modal
title="编辑"
visible={visible}
onOk={okHandler}
onCancel={hideHandler}
getContainer={false}
>
<Form
{...layout}
form={form}
initialValues={ {
status: record.status || STATUS[0].key,
} }
>
<Form.Item
label="标题"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item
label="状态"
name="status"
rules={[
{
required: true,
},
]}
>
<Select>
{
STATUS.map(v => (
<Select.Option key={v.key} value={v.key}>{v.title}</Select.Option>
))
}
</Select>
</Form.Item>
</Form>
</Modal>
</span>
);
};
export default Edit;
然后调整List.jsx,增加增删改入口:
import React from 'react';
import { Table, Button, Popconfirm } from 'antd';
import STATUS from './status';
import Edit from './Edit';
class List extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [{
id: 1,
title: 'React简单示例演示任务',
status: 'processing',
}, {
id: 2,
title: '博客更新',
status: 'pending',
}]
};
this.maxId = 2;
}
columns = [{
title: '标题',
dataIndex: 'title',
}, {
title: '状态',
dataIndex: 'status',
render: key => STATUS.find(v => v.key === key).title,
}, {
title: '操作',
render: (text, record) => (
<div style={ { display: 'flex' } }>
<Edit record={record} onOk={this.editHandler.bind(this, record.id)}>
<Button type="link">编辑</Button>
</Edit>
<Popconfirm title="确认删除?" onConfirm={this.deleteHandler.bind(this, record.id)}>
<Button type="link" danger>删除</Button>
</Popconfirm>
</div>
),
}];
createHandler = (values) => {
this.setState({
list: [...this.state.list, {...values, id: ++this.maxId}],
});
};
editHandler = (id, values) => {
console.log(id, values);
this.setState({
list: this.state.list.map(v => v.id === id ? {...values, id} : v),
});
};
deleteHandler = id => {
this.setState({
list: this.state.list.filter(v => v.id !== id),
})
};
render() {
return (
<div>
<div>
<Edit record={ {} } onOk={this.createHandler}>
<Button type="primary">创建</Button>
</Edit>
</div>
<Table dataSource={this.state.list} columns={this.columns} rowKey="id" />
</div>
);
}
};
export default List;
最终效果: