安装create-react-app脚手架
- npm install -g create-react-app
创建你的todo-list项目
create-react-app todo-list
注意npm命名限制,项目名称不能含有大写字母。
清除项目中不必要的文件
src目录中的:App.css, App.test.js, logo.svg, serviceWorker.js文件
public目录中的: manifest.json文件
其中manifest.json,serviceWorker.js属于pwa的配置文件,有兴趣可以了解一下。
pwa 让网页写好以后,用户访问了一次之后,就可以把我们的网页当作app来用,可以不用联网。
在手机上或者电脑桌面上通过点击快捷方式来打开页面。
他的图标和快捷方式是通过public中manifest.json去定义的
之前删除的文件在剩下的文件有引入使用,现在将其删除
- App.js删除下列代码注释部分
import React, { Component }from 'react';
// import logo from './logo.svg';
// import './App.css';
class App extends Component {
render(){
return (
{
/*
Edit src/App.js
and save to reload.
Learn React
*/
}
hello react
);
}
}
export default App;
- index.js 删除一下注释部分
import React from 'react';
import ReactDOM from 'react-dom';
// import './index.css';
import App from './App';
//import * as serviceWorker from './serviceWorker'; // pwa 引入
ReactDOM.render( , document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
// serviceWorker.unregister(); // pwa 使用
- public中的index.html文件,删除以下注释部分代码
todo-list
项目目录解析
yarn.lock -- 包锁文件
README.MD -- 项目介绍
package.json -- node的包文件
.gitignore -- 使用git的时候可以将不想上传到git的文件在此处标记
node_modules -- 项目依赖包
index.html 项目首页模版
favicon.ico 网页图标
index.js 入口js文件
app.js 万年老二组件
jsx语法
jsx语法规定,在return中的最外层只能含有一个标签。
为此你可以使用div也可以使用react提供的Fragment占位符,他其实也是一个组件。
在js中写html标签。就称为jsx语法
render()函数中return => html标签或者组件名加括号,组件必须以大写字母开头
jsx中使用变量,需要使用{}包裹
现在我们将App.js改造成如下代码。
通过npm run start 启动你的项目
import React, { Component, Fragment } from 'react';
class App extends Component {
render(){
return (
- react
);
}
}
export default App;
react的响应式思想和事件绑定
定义数据
之前我们已经将todo-list的结构搭好了。现在需要实现功能。
不要直接操作dom
通过改变数据改变dom
此时我们需要准备两组数据,1组数据存储input里面的值,1组数据存储列表中的值。
-
如何定义数据?
一个类必定有一个构造函数,并且他是最先执行的函数,我们可以将数据存在这个构造函数中
constructor 即为App类的构造函数,构造函数中有state属性,他是用来存放这个类的变量的。
因此数据就定义在state中。
constructor 构造函数还有一个super()方法,他可以帮助App类调用他的父类(Component)的属性。
使用箭头函数不然this指向出错
只能通过setState方法去改变state中的变量
代码如下
import React, { Component, Fragment }from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
inputValue: '',// 用来存储 input框中的 value值。
list:[] // 用来存储 每一个li的 value值。
}
}
render(){
return (
- react
);
}
}
export default App;
绑定数据
我们上面已经定义好了数据,现在将数据绑定到对应的dom上
这样方便我们通过数据改变dom
react jsx语法中,绑定数据到dom上,使用{} 包裹。 -- value = {this.state.inputValue}
列表数据绑定也是一样,在{}中写js表达式,我们可以通过es5的map函数遍历list数组获得item值,和他的下标
然后通过return返回一个li标签,返回之前,将item绑定到li的value值,将index作为li的key
注意的是,实际开发中将index作为key值是一个错误的做法。
import React, { Component, Fragment }from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
inputValue: '',// 用来存储 input框中的 value值。
list:['西瓜','苹果'] // 用来存储 每一个li的 value值。
}
}
render(){
return (
{
this.state.list.map((item, index) => {
return (
-
{item}
)
})
}
);
}
}
export default App;
react的事件绑定
我们现在需要绑定input的onChange事件,以此达到input的value值的变化和我们数据inputValue变化一致
react的事件绑定和原生的区别就是第二个单词首字母要大写,onChang
在onChange事件中绑定handleInputChange()方法,传入事件对象,获取target值,他的value就是当前input的value值
再通过this.setState()方法区改变组件中inputValue的值。
要注意的是,react中只能通过setState方法改变state中的属性。
import React, { Component, Fragment }from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
inputValue: '',// 用来存储 input框中的 value值。
list:['西瓜','苹果'] // 用来存储 每一个li的 value值。
}
}
handleInputChange = (e) => {
this.setState({
inputValue: e.target.value
})
console.log(e.target)
}
render(){
return (
{
this.state.list.map((item, index) => {
return (
-
{item}
)
})
}
);
}
}
export default App;
如何实现Todolis的增删功能
增加思路 在input框中输入要添加的字段,点击提交,提交绑定一个方法,将inputValue的值添加到list数组中
删除思路 在每一个li中绑定点击事件,在点击的时候,传入当前li的下标,在事件方法中通过下标删除list中的对应元素
要注意的时,在传入index的时候我尝试过直接在方法名后面传入,但是会报错,改在bind()方法中第二个参数传入,就没有问题了
state中的属性数据,只能通过this.setState({})方法修改,不能直接修改。
在使用splice的时候踩了一个坑,list = list.splice(index, 1)
这是一行错误代码,这样赋值,list等于是你删除的哪个元素组成的数组,splice会改变原数组,返回被删除的数组。无需再赋值
import React, { Component, Fragment } from 'react';
class App extends Component {
// 定义数据,一个类必定有一个构造函数,他是最先执行的函数
constructor(props){
super(props); // App继承Component类,所以要通过super(props)调用他的父类的属性
this.state = {
inputValue: '', // input框的value
list: [] // 列表的数据
}
}
handleInputChange = (e) => { // 使用箭头函数不然this指向出错
this.setState({ // 只能通过setState去改变state中的变量
inputValue : e.target.value
})
console.log(e.target)
}
// 增加方法
handleBtnClick = () => {
this.setState({
list : [...this.state.list, this.state.inputValue],
inputValue: ''
})
}
// 删除方法
handleItemDelet = (index) => {
console.log(index)
let list = [...this.state.list];
// list = list.splice(index, 1) // 这是一行错误代码,这样赋值,list等于是你删除的哪个元素组成的数组
list.splice(index, 1)
console.log(list)
this.setState({
list : [...list]
})
}
render(){
return (
{
this.state.list.map((item, index) => {
return - {item}
// 实际编程之中使用index做key值是一个非常不好的习惯
})
}
);
}
}
export default App;
jsx细节补充
注释用大括号包裹,单行注释要换行
添加样式使用 className ,class会被解析成类
dangerouslySetInnerHTML = {js表达式}
dangerouslySetInnerHTML = {{ __html: item }} 多一个花括号表示一个js对象
// 如果需要显示input框中内容中的标签效果 就这么写。但是这样写容易造成xss攻击 对应的标签中就不需要写item了
lable标签 使用htmlFor引入到指定标签中
render(){
return (
{/* 他其实是一个组件 */ }
输入内容
{
this.state.list.map((item, index) => {
return (
-
) // 实际编程之中使用index做key值是一个非常不好的习惯
})
}
);
}