一、 使用create-react-app创建react应用
1.1. react脚手架
- xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
- 包含了所有需要的配置(语法检查、jsx编译、devServer…)
- 下载好了所有相关的依赖
- 可以直接运行一个简单效果
- react提供了一个用于创建react项目的脚手架库: create-react-app
- 项目的整体技术架构为: react + webpack + es6 + eslint
- 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化
1.2. 创建项目并启动
第一步,全局安装:npm i -g create-react-app
第二步,切换到想创项目的目录,使用命令:create-react-app hello-react
第三步,进入项目文件夹:cd hello-react
第四步,启动项目:npm start
1.3. react脚手架项目结构
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js --- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js ---- 组件单元测试的文件(需要jest-dom库的支持)
1.4. 功能界面的组件化编码流程(通用)
1. 拆分组件: 拆分界面,抽取组件
2. 实现静态组件: 使用组件实现静态页面效果
3. 实现动态组件
3.1 动态显示初始化数据
3.1.1 数据类型
3.1.2 数据名称
3.1.2 保存在哪个组件
3.2 交互(从绑定事件监听开始)
二、案例
1. TodoList分析
1.拆分组件、实现静态组件,注意:className、style的写法
2.动态初始化列表,如何确定将数据放在哪个组件的 state中?
——某个组件使用:放在其自身的 state中
——某些组件使用:放在他们共同的父组件 state中(官方称此操作为:状态提升)
3.关于父子之间通信:
1.【父组件】给【子组件】传递数据:通过 props传递
2.【子组件】给【父组件】传递数据:通过 props传递,要求父提前给子传递一个函数
4.注意 defaultChecked 和 checked的区别,类似的还有: defaultValue 和 value, checked必须要写onChange方法配合使用
5.状态在哪里,操作状态的方法就在哪里
2. 代码
(1)App.jsx
1 import React, { Component } from 'react'
2 import Header from './components/Header'
3 import List from './components/List'
4 import Footer from './components/Footer'
5 import './App.css'
6
7 export default class App extends Component {
8 //状态在哪里,操作状态的方法就在哪里
9
10 //初始化状态
11 state = {todos:[
12 {id:'001',name:'吃饭',done:true},
13 {id:'002',name:'睡觉',done:true},
14 {id:'003',name:'打代码',done:false},
15 {id:'004',name:'逛街',done:false}
16 ]}
17
18 //addTodo用于添加一个todo,接收的参数是todo对象
19 addTodo = (todoObj)=>{
20 //获取原todos
21 const {todos} = this.state
22 //追加一个todo
23 const newTodos = [todoObj,...todos]
24 //更新状态
25 this.setState({todos:newTodos})
26 }
27
28 //updateTodo用于更新一个todo对象
29 updateTodo = (id,done)=>{
30 //获取状态中的todos
31 const {todos} = this.state
32 //匹配处理数据
33 const newTodos = todos.map((todoObj)=>{
34 if(todoObj.id === id) return {...todoObj,done}
35 else return todoObj
36 })
37 this.setState({todos:newTodos})
38 }
39
40 //deleteTodo用于删除一个todo对象
41 deleteTodo = (id)=>{
42 //获取原来的todos
43 const {todos} = this.state
44 //删除指定id的todo对象
45 const newTodos = todos.filter((todoObj)=>{
46 return todoObj.id !== id
47 })
48 //更新状态
49 this.setState({todos:newTodos})
50 }
51
52 //checkAllTodo用于全选
53 checkAllTodo = (done)=>{
54 //获取原来的todos
55 const {todos} = this.state
56 //加工数据
57 const newTodos = todos.map((todoObj)=>{
58 return {...todoObj,done}
59 })
60 //更新状态
61 this.setState({todos:newTodos})
62 }
63
64 //clearAllDone用于清除所有已完成的
65 clearAllDone = ()=>{
66 //获取原来的todos
67 const {todos} = this.state
68 //过滤数据
69 const newTodos = todos.filter((todoObj)=>{
70 return !todoObj.done
71 })
72 //更新状态
73 this.setState({todos:newTodos})
74 }
75
76 render() {
77 const {todos} = this.state
78 return (
79
80
81
82 todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo}/>
83
85
86 )
87 }
88 }
(2) Header.jsx
1 import React, { Component } from 'react'
2 import PropTypes from 'prop-types'
3 import {nanoid} from 'nanoid'
4 import './index.css'
5
6 export default class Header extends Component {
7
8 //对接收的props进行:类型、必要性的限制
9 static propTypes = {
10 addTodo:PropTypes.func.isRequired
11 }
12
13 //键盘事件的回调
14 handleKeyUp = (event)=>{
15 //解构赋值获取keyCode,target
16 const {keyCode,target} = event
17 //判断是否是回车按键
18 if(keyCode !== 13) return
19 //添加的todo名字不能为空
20 if(target.value.trim() === ''){
21 alert('输入不能为空')
22 return
23 }
24 //准备好一个todo对象
25 const todoObj = {id:nanoid(),name:target.value,done:false}
26 //将todoObj传递给App
27 this.props.addTodo(todoObj)
28 //清空输入
29 target.value = ''
30 }
31
32 render() {
33 return (
34
35 onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/>
36
37 )
38 }
39 }
(3) List.jsx
1 import React, { Component } from 'react'
2 import PropTypes from 'prop-types'
3 import Item from '../Item'
4 import './index.css'
5
6 export default class List extends Component {
7
8 //对接收的props进行:类型、必要性的限制
9 static propTypes = {
10 todos:PropTypes.array.isRequired,
11 updateTodo:PropTypes.func.isRequired,
12 deleteTodo:PropTypes.func.isRequired,
13 }
14
15 render() {
16 const {todos,updateTodo,deleteTodo} = this.props
17 return (
18
19 {
20 todos.map( todo =>{
21 return <Item key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo}/>
22 })
23 }
24
25 )
26 }
27 }
(4) Item.jsx
1 import React, { Component } from 'react'
2 import './index.css'
3
4 export default class Item extends Component {
5
6 state = {mouse:false} //标识鼠标移入、移出
7
8 //鼠标移入、移出的回调
9 handleMouse = (flag)=>{
10 return ()=>{
11 this.setState({mouse:flag})
12 }
13 }
14
15 //勾选、取消勾选某一个todo的回调
16 handleCheck = (id)=>{
17 return (event)=>{
18 this.props.updateTodo(id,event.target.checked)
19 }
20 }
21
22 //删除一个todo的回调
23 handleDelete = (id)=>{
24 if(window.confirm('确定删除吗?')){
25 this.props.deleteTodo(id)
26 }
27 }
28
29
30 render() {
31 const {id,name,done} = this.props
32 const {mouse} = this.state
33 return (
34 onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>
35
39
40
41 )
42 }
43 }
3. 效果