一.使用create-react-app创建react应用
1.react脚手架
- xxx脚手架:用来帮助程序员快速创建一个基于xxx库的模板项目
- 包含了所有需要的配置(语法检查,jsx编译,devServer…)
- 下载好了所有相关的依赖
- 可以直接运行一个简单的效果
- react提供了一个用于创建react项目的脚手架库:create-react-app
- 项目的整体技术架构为:react+webpack+es6+eslint
- 使用脚手架开发项目的特点:模块化,组件化,工程化
2.创建项目并启动项目
- 全局安装:npm install -g create-react-app (第一次进行全局安装之后,就不需要执行此操作了)
- 切换到想创建项目的目录,使用命令:create-react-app hello-react(项目名称)
- 进入项目文件夹: cd hrllo-react
- 启动项目:npm start
public文件夹介绍
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- %PUBLIC_URL%代表public文件夹的路径 -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<!-- 开启理想视口,用于做移动端网页的适配 -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- 用于配置浏览器页签+地址栏的颜色(仅支持安卓手机浏览器) -->
<meta name="theme-color" content="red" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<!-- 用于指定网页添加到手机主屏幕后的图标 -->
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- 应用加壳时的配置文件 -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<!-- 若浏览器不支持js则展示标签中的内容 -->
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
src文件夹介绍
创建项目基础知识
例子:
import React, { Component } from "react";
import Hello from './Hello/Hello'
import Welcome from './Welcome/Welcome'
//分别暴露组件
//创建类似组件,和前面练习的代码一样
export default class App extends Component {
render() {
return (
<div>
<h2><Hello /></h2>
<h2><Welcome /></h2>
</div>
)
}
}
3.样式模块化
如果不使用样式模块化,当父组件内存在多个子组件,并且多个组件中含有相同的名称时会造成样式的覆盖,因此在不想改变名称下,引入了样式模块化。
import React,{Component} from "react";
// 采用了样式模块化,防止多组件时样式被覆盖
import hello from '../Hello/Hello.module.css'
//分别暴露组件
//创建类似组件,和前面练习的代码一样
export default class Hello extends Component{
render(){
return <h2 className={hello.title}>Hello React!</h2>
}
}
4.功能化界面的组件化编码流程
- 拆分组件:拆分界面,抽取组件
- 实现静态组件:使用组件实现静态页面的效果
- 实现动态组件:
- 动态显示初始化数据
- 数据类型
- 数据名称
- 保存在哪个组件
- 交互(从绑定事件监听开始)
- 动态显示初始化数据
5.todoList中的注意事项
-
当辅助见向子组件传递内容,较多的时并且传递的内容都属于同一个对象则可以利用扩展运算符。
import React, { Component } from 'react' import Item from '../Item/index.jsx' import './index.css' export default class List extends Component { render() { //因为父组件是todos={},所以结构赋值中使用的是todos const { todos } = this.props return ( <ul className="todo-main"> { todos.map((todo) => { //{...todo}批量传递 return <Item key={todo.id} {...todo} /> }) } </ul> ) } }
-
checked不能够进行后续的更改,要想要改以后就必须使用onChange(),所以一般使用defaultChecked。但是defaultChecked只在第一次起作用
例子:
-
在生成一个唯一的id的时候,可以借助第三方资源库uuid但是由于uuid内容太多所以我们可以安装nanoid来代替uuid
例子:
import React, { Component } from 'react' import {nanoid} from 'nanoid' import './index.css' export default class Header extends Component { handleKeyUp = (event) => { //解构赋值获取keyCode,target const { keyCode, target } = event //判断是否是回车事件 if (keyCode !== 13) return //添加的todo名字不能为空,trim()去除空格 if(target.value.trim()===""){ alert("输入不能为空") return } console.log(target.value); //准备好一个todo对象 const todoObj = { // uuid专门生成唯一id的一个库 //安装uuid的方法:方式一:利用yarn :yarn add uuid;因为uuid内容较大,所以安装nanoid:yarn add nanoid方式二:利用npm: npm i uuid,因为uuid内容较大,所以安装nanoid id: nanoid(), name: target.value, done: false } this.props.addtodo(todoObj) target.value="" } render() { return ( <div className="todo-header"> {/* onKeyUp:监听键盘按下事件 */} <input type="text" onKeyUp={this.handleKeyUp} placeholder="请输入你的任务名称,按回车键确认" /> </div> ) } }
-
为什么对于react中绑定的函数的返回结果需要写成函数?(利用的高阶函数)
调用render函数时获取vdom,发现标签存在事件绑定-> 先执行代码中的方法-> 获取到的是undefined。当事件被触发时,无函数可执行
总结:
-
原生js事件绑定的值只有在事件被触发时才会执行
-
react中的事件绑定会在render函数调用时被触发,函数的返回值才是函数被触发时执行的逻辑代码。
例子:
import React, { Component } from 'react' import './index.css' export default class Item extends Component { //判断鼠标是否进来 state = { mouse: false } handleMouse = (bool) => { return () => { this.setState({ mouse: bool }) } } render() { const { name, done } = this.props return ( <li style={{ backgroundColor: this.state.mouse ? '#ddd' : 'white' }} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}> <label> {/* checked不能够进行后续的更改,要想要改以后就必须使用onChange() 所以一般使用defalutChecked */} <input type="checkbox" defaultChecked={done} /> <span>{name}</span> </label> <button className="btn btn-danger" style={{ display: this.state.mouse?'block':'none' }}>删除</button> </li> ) } }
-
-
如果不想使用高阶函数可以在标签中使用箭头函数然后把相应的方法放在箭头函数中。
import React, { Component } from 'react' import './index.css' export default class Item extends Component { //判断鼠标是否进来 state = { mouse: false } handleMouse = (bool) => { return () => { this.setState({ mouse: bool }) } } //切换内容 handleCheck = (id) => { return (event) => { this.props.updateTodo(id, event.target.checked) } } //删除一个todo的回调 handleDelete=(id)=>{ if(window.confirm('确定删除吗?')){ this.props.deleteTodo(id) } } render() { const { id, name, done } = this.props return ( <li style={{ backgroundColor: this.state.mouse ? '#ddd' : 'white' }} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}> <label> {/* checked不能够进行后续的更改,要想要改以后就必须使用onChange() 所以一般使用defalutChecked */} <input type="checkbox" checked={done} onChange={this.handleCheck(id)} /> <span>{name}</span> </label> <button onClick={()=>{this.handleDelete(id)}} className="btn btn-danger" style={{ display: this.state.mouse ? 'block' : 'none' }}>删除</button> </li> ) } }
6.todoList案例总结:
-
拆分组件,实现静态组件。注意:className,style的写法
-
动态初始化列表,如何确定将数据放在哪个组件的state中?
- 某个组件使用:放在自身的state中
- 某些组件的使用放在他们共同的父组件state中(官方称此操作为:状态提升)
-
关于父子间通信
- 【父组件】给【子组件】传递数据:通过props传递
- 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
-
注意defaultChecked和checked的区别,类似的还有defaultValue和value
-
状态在哪里,操作方法就在哪里