react/既简单又可以做假账的小账本
accounts-app
simple account app
react/一个功能简单的小账本,记录现金的流入流出/可以做假账(随时编辑历史记录)
GitHub源地址:https://github.com/0rainge/accounts-app
0. 项目总结
0-1. 展示
0-2. 功能点
- 展示记录(设置表格,展示每条记录)
- 创建记录(设置表单,输入记录:时间,事项,收支金额)
- 计算并展示总金额(设置数据展示卡片,计算收入、支出、总金额并展示)
- 更新/删除记录(在表单中实现数据的更新和删除)
1. 思路
1-0 搭建项目
- 搭建脚手架:create-react-app
- 引入样式bootstrap样式库,从bootCDN中找一个css复制link标签 https://www.bootcdn.cn/twitter-bootstrap/
- 新建文件夹component,实现组件
1-1 records列表和record行记录
- 实现Records组件,渲染一个记账表格
- 实现Record组件,渲染一行表格内容用来存一条数据内容,通过
调用数据 - 设置Records的state,通过map传递给Record(之后会从API里取)(设置数据静态类型)
1 | {this.state.records.map((record) => <Record record={record} / >)} |
1-2 页面组件载入后的请求数据
- 利用组件生命周期:componentDidMount
- 通过jquery创建ajax发送请求,加载数据(通过then返回成功的结果response或失败的结果error),设置状态error和isLoaded
- 或通过axios(基于promise的http请求库)创建ajax发送请求,(链式调用then和catch处理返回数据或捕获错误),设置状态同上
- 根据状态(加载中、加载失败、加载成功)显示不同结果:取值、判断、返回html或{}包含的动态数据
1-3 设置API
- 建立文件夹utils/RecordsAPI.js 设置API
- 定义常量 api = process.env.NAMEE || XXXXXX
- 导出api,在其他地方引入
- package.json的start中设置全局变量NAMEE;或者在根目录新建文件.env.development.local
- 定义NAMEE = API_URL
- npm start时默认找.env.development.local等其他几个文件设置环境变量
- 注意字符串的拼接:嵌套模版
`
${api}/records` - 封装axios的ajax方法(get,post,put,delete)
1-4 设置Record表单输入数据
- 设置表单组件
- render return中定义表单from,包含3个input(type,name,value,placeholder, onChange),1个btn(type),input的传入name,样式用bootstrap
- 设置开启规则:三个表单全有值,开启按钮,通过{}传入函数动态赋值disable属性;执行方法和传入方法的区别:是否有()
- 监听表单内容操作state:设置onchange方法
- event.target.name 和 event.target.value 分别代表事件发生的组件和事件发生组件内的值(event是this)
1-5 增加记录
- 思路:
- 提交数据,发起请求,到API中
- 服务器收到请求返回一个id,
- id再加上其他数据(date,title,amount)到table组件中,重新渲染
(只要发起一条请求用来创建数据,创建完不用发送请求)做法:组件之间传递消息如form组件向table组件传递信息
- 步骤:
- 在表单中设置监听函数
- 绑定事件句柄
- 在API文档中创建create方法的API:调用axios的post方法,传入body和api地址
- 事件句柄调用api
- 调用api后设置链式调用的then和catch,使用response和error(此处测试)
- 子组件和父组件传递数据:实现发送数据后更新表单
- 点击btn清空input——设置状态
- table添加数据:通过扩展运算法,把原来的状态和传入参数混合,更新状态
1-6 更新记录
- 添加编辑/更新/取消按钮(点击编辑进入编辑状态,点击更新发送请求,点击取消返回(新增状态edit进行控制)
- 根据当前edit设置显示逻辑:从td返回不同内容(不可编辑——返回值,编辑状态——返回input,注意设置defaultValue),编辑按钮和返回按钮调用同一个函数(布尔)进行状态切换
- 设置api发送put请求(需要传个id和需要更新的内容refs过去)
- 更新table(仿照redux——在数组中更新元素:找到数据中那个数据,替换,返回新的数组,render更新)
- table和record之间共享数据
- 更新table的方法:传入的全部数据和更新过的数据,通过map更新
1-7 删除记录
- 思路:
- 绑定监听函数
- 发送请求把记录删除
- 更新父组件
- 实现:
- 按钮:上绑定监听函数
- 子组件函数:在组件中设置监听函数
- API:添加deleteAPI
- 子组件函数:通过监听函数调用api函数
- 父组件函数:由子组件调用——参数是子组件的,参数更新了父组件的状态,实现删除
- 子组件:调用父组件传来的函数更新页面
1-7 计算金额
统计收入(正数amount相加),支出(负数amount相加),余额(收入和支出相加)
- 思路:
- 显示卡片
- 计算数字
- 实现:
- 设置组件,返回html代码,传入数值
- 父组件中设置计算函数返回给子组件
问题记录:
1. vs code react如何自动补全标签
https://blog.csdn.net/shaleilei/article/details/82984228
2. chrome安装react调试插件
https://github.com/facebook/react-devtools/blob/master/README.md#the-react-tab-doesnt-show-up
3. 报错
1 | index.js:1446 Warning: Each child in an array or iterator should have a unique "key" prop. |
4. mock模拟服务器端数据
- 通过API创建数据 https://www.mockapi.io/
- json server:https://github.com/typicode/json-server
1 |
|
5. mock模拟收到数据
- 在终端进行curl
1 | curl http://5c544a2ea659410014eeeb2c.mockapi.io/api/v1/records |
- postman使用get方法
- 浏览器自带fetch方法
参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch1
2
3
4
5
6
7
8
9fetch('http://localhost:3004/records ')
.then(response => response.json())
.then(data => {
console.log(data)
});
分析这个函数:接url接then函数返回一个promise,后面跟一个json,最后输出
只有当网络故障或请求阻止才会被标记为reject
6. mock模拟发送数据
向远程API发送数据
向本地json server发送数据
7. 父组件向字组件传递数据
通过map枚举,把值赋给另一个组件:有几条数据,调用几次组件,组件的内容通过父组件传入
子组件用this.props.record.date等来调用父组件的值
1 |
|
8. 扩展运算法: …
扩展运算符用于扩展一个哈希或数组,ES6的写法
1 | 1. {...record} = {id:record.id} {date:record:date} |
9. 组件分析:
组件:可以看成是一个函数/类,可以继承自Component,也可以自定义不继承
看成函数:不继承自Component,通过函数传递数据
- 声明:扩展自Component
- 构造器:执行父组件构造函数,设置状态state
- 方法:自定义各种方式,实现增删改查、调接口、计算数值
- render函数:定义变量和代码逻辑,变量可以是css样式{},html代码(),state改变就会重新render
- return:返回html代码
- 导出组件:export default + 组件名(或者在定义组件时就导出)
10. ES6解构赋值
1 | const {err,isLoaded,records} = this.state |
11. 库的按需导入
1 | import {getJson} from 'jquery' |
到时候就直接用getJson方法
12. 静态类型的检查机制
导入静态类型检查库:propTypes,设置组件的proptypes对象,key是state/porps;value是proptypes的数据类型
13. 使用环境变量代替API地址
重构API变量,放入统一的文件中,把环境变量(URL)单独放入一个文件中
环境变量:‘REACT_APP_’开头,‘’
14. bootstrap常用类名
外边距/内填充
- 第一位
- m:margin
- p:padding
- 第二位
- t:top,
- b:bottom
- l:left
- r:right
- a:all
- x:left和right
- 第三位
- auto:auto
- md:1.5rem
- lg :3rem
- 1:$spacer-x
- 2:$spacer-x * 1.5
- 3:$spacer-y * 3
还有:网格,排版,表格,表单,按钮,图片,下拉菜单,按钮组,输入框,导航栏,面包屑,分页,标签,缩略图,进度条,多媒体列表,面板等
更多常用类名参考:https://www.cnblogs.com/sunxirui00/p/7580850.html
https://v4.bootcss.com/docs/4.0/getting-started/introduction/
15. 组件的监听方法:on+动作
创建事件句柄:自定义方法重写形如:handleAction(event)
默认监听方法形如:onAction
- onSubmit:表单提交
- onChange:input内容改变
默认监听方法onAction通常会绑定自定义方法handleAction:1
onAction = this.handleAction.bind(this)
16. 阻止默认事件
1 | event.preventDefault(); |
17. 发送数据的数据类型
把字符串类型转换为整形
xx:Number.parseInt(this.state.xx,0)
18. 父组件向子组件传值/函数
目的:实现发送数据后更新表单的功能(当子组件form向API发出post请求后收到response,后调用父组件函数更新table,只有发送一次请求),将父组件函数传递给子组件,通过子组件调用父组件函数改变父组件状态。
- 创建父组件方法Action
把父组件方法Action赋值给子组件句柄handleAction,类似把handleChange赋值给onChange
1
handleAction = this.Action.bind(this)
子组件触发条件,通过this.props.handleAction调用这个函数(传入参数是子组件状态,方法内数据为父组件状态)
- 父组件的状态得到更新
19. 更新数据:获取input的内容
获取:使用input框的3个值,在input中设置ref属性:ref = “date/value/amount”
使用:在自定义方法中使用this.refs.date.value
20. 关于api发送请求的疑问
向api发送数据,为什么会返回这个发送过去的数据以及id呢?
21. 关于map
1 |
|
如果是不需要改的记录就把它和更新的data放在一起,item是每一项,index是该项的索引
22. 关于key
用于记录多个相同组件
1 | <Record |
23. 关于filter
1 |
|
24. 动态设置组件样式
传入参数bg-${type}改变样式
1 | <div className={`card-header bg-${type} text-white`} > |