项目结构
上一章我们创建完了一个React项目,现在打开我们的项目文件夹,我们能看到node_modules
,public
,和src
三个子文件夹以及package.json
和README
等文件。注意src
这个文件夹,我们之后要把重心放在src
这个文件夹里。
我们开始做一个Todo项目吧
第一步:打开public文件夹下的index.html
我们可以看到html的文件结构,熟悉html的同学应该很容易能看懂了,这是一个再简单不过的结构了,我们把文件内容替换成以下内容,当然你也可以起一个你喜欢的名字,加一张你喜欢的图标,不过,我们一切从简,注意body
里的id
,这很重要。
<!DOCTYPE html>
<html>
<title>React Todo</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
第二步:打开src下的App.js文件
这个文件就是我们的主页所在的文件了,但是为什么不放在index.js里呢?按我的个人理解,这就是一个良好的代码风格,而且之后还会涉及到页面路由等,因为你的网页不可能只是一个主页,还会有许多的子页面,把这些子页面单独放在一个文件里,还可以作为模板重复利用,而且在index.js里我们可以做一些额外的配置,比如使用中间件等,这样模块化开发会让代码可读性更强。(我随便说的,大佬请指正!)好了,废话不多说,我们先把代码放出来。
import React, { Component } from "react";
class App extends Component {
render() {
return (
<div className="todo">
<div className="header">
<form>
<input placeholder="输入任务">
</input>
<button type="submit">添加</button>
</form>
</div>
</div>
);
}
}
export default App;
点击保存,然后刷新我们的网页看看(一般来说保存了就会自动刷新,记得先npm start
一下)
第三步:添加功能
现在就算你输入了一个任务,你也点了添加了,但是好像并没有发生什么事情。当然了,你都还没添加功能进去呢,难道凭空给你生出来?
先别急,我们想想我们做一个todo项目需要什么功能?
- 添加任务
- 完成任务
- 删除任务
- 修改任务
我们先来实现添加任务
我们在render()
前插入以下代码,我们定义一个addItem函数
constructor(props) {
super(props);
this.addItem = this.addItem.bind(this);
}
addItem(e) {
}
记得我们在render()
里插入了一个form
标签吗?我们需要在form
提交的时候触发addItem
函数,我们在form标签里加入一个onSubmit={this.addItem}
,像这样:
<form onSubmit={this.addItem}>
但是addItem函数的参数怎么来呢?那么,我们就要想办法获取input输入框的内容。有两种方法:
- 非受控组件(即ref)
- 受控组件(即onChange或onClick等方法)
我们暂时采用第一种方法,第二种方法大家可以自行尝试,现在代码变成了这样:
<input ref={(a) => this._inputElement = a }
placeholder="输入任务">
我们来验证一下这样是否可行,我们在addItem
函数里让输入框的值在控制台显示一下。
addItem(e) {
console.log(this._inputElement.value)
}
但是这个时候我们会发现浏览器好像会自动刷新,然后控制台的内容一下就没了,那怎么办呢?我们加一行代码:
addItem(e) {
console.log(this._inputElement.value)
e.preventDefault();
}
这能阻止浏览器的默认行为,这里就是不让它刷新了
好了,我们已经成功获取到输入框的值了,接下来,我们要怎么把它存起来?没错,我们用state来储存我们的值。
我们在super(props);
后面初始化一下state
,并在里面放一个数组类型的items
。
...
constructor(props) {
super(props);
this.state = {
items: []
};
...
然后我们在addItem
函数里,将输入框的值追加给这个items
数组
addItem(e) {
if (this._inputElement.value !== "") {
var newItem = {
text: this._inputElement.value,
key: Date.now()
};
this.setState((prevState) => {
return {
items: prevState.items.concat(newItem)
};
});
this._inputElement.value = "";
}
console.log(this.state.items);
e.preventDefault();
}
但是我们发现好像控制台显示的有些问题,它并没有将我们刚刚添加进去的值显示出来,而是显示的前面添加过的值,这是因为React的state状态更新机制引起的,我们已经实现了添加功能了,开心!下面是完整代码。
import React, { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
this.state = {
items: []
};
this.addItem = this.addItem.bind(this);
}
addItem(e) {
if (this._inputElement.value !== "") {
var newItem = {
text: this._inputElement.value,
key: Date.now()
};
this.setState((prevState) => {
return {
items: prevState.items.concat(newItem)
};
});
this._inputElement.value = "";
console.log(this.state.items);
e.preventDefault();
}
render() {
return (
<div className="todo">
<div className="header">
<form onSubmit={this.addItem}>
<input ref={(a) => this._inputElement = a }
placeholder="输入任务">
</input>
<button type="submit">添加</button>
</form>
</div>
</div>
);
}
}
export default App;
总结
今天先到这,我们已经能实现了获取表单值并把它添加到state里了,下一章我们将会做更多的事,大家可以先想想应该怎么把数组里的值显示出来,然后该怎么去修改或删除它!