# React02
# 回顾
React 用于构建用户界面的 JavaScript 库
国内三大框架
Vue [需要记忆一些写法,指令...]
React [在写大量的 JS 代码]
Augular [大型和重型的项目 大而全的框架] JS 框架
框架的热度,流不流行 github 的 start npmjs 包下载量
公司使用任何框架 在于公司目前技术栈的选择
React
编写方式:
脚本引入方式 script src 属性
react.js React 对象 管理 React 虚拟 DOM
react-dom.js reactDOM 对象 渲染操作 DOM 的
babel.js 转义 JS 语法 转义 JSX 语法为 JS 代码
JSX 语法 可以认为和 html 语法差不多,一些细节的属性,注意比如说 class className
{}
JS 代码范围 里面的代码会被 JS 解析执行
组件封装方式:
rfc 函数组件 react function component
之前无状态组件
之前函数组件无法使用 state 组件状态 hook
16.8 版本已经可以
rcc 类组件 react class component 功能更为全面 之前 react 主流开发组件方式就是 rcc
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JSX语法</title>
</head>
<body>
<div id="root"></div>
<script src="/babel.min.js"></script>
<script src="/react.development.js"></script>
<script src="/react-dom.development.js"></script>
<script type="text/babel">
// 外部传入组件参数 状态 数据
function Hero(props) {
// es6 解构语法
const{name,job,price} = props
return (
<div>
<h1>名称:{name}</h1>
<h1>职业:{job}</h1>
<h1>价格:{price}</h1>
</div>
);
}
// 调用组件
// 调用方式一 函数调用方式
let vNode = Hero({
name:'后裔',job:'射手',price:6800
})
// 调用方式二 组件标签方式调用
// JS代码需要用{}包裹
vNode =(<div>
<Hero name="凯" job="打野" price="13888"/>
<Hero name="蔡文姬" job="辅助" price="13888"/>
<Hero name="瑶" job="辅助" price="13888"/>
<hr/>
{Hero({name:'后裔',job:'射手',price:6800})}
</div>)
ReactDOM.render(vNode, document.getElementById("root"));
</script>
</body>
</html>
# 类组件
以类的方式封装组件 功能更为全面一些,早期(16.8 版本以前 )函数组件无法支持 state组件状态,组件生命周期
,只能使用类组件
组件 hook 函数组件使用 state 和生命周期
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>类组件</title>
</head>
<body>
<div id="root"></div>
<script src="/babel.min.js"></script>
<script src="/react.development.js"></script>
<script src="/react-dom.development.js"></script>
<script type="text/babel">
// 类组件
// es6语法中class是类的声明关键字
// extends继承 可以得到 复用父类的功能
// 继承React组件
// 类名也是大驼峰
class Hello extends React.Component{
// 方法
render(){
return <h1>hello 类组件</h1>
}
}
// 调用方式1:实例化对象使用
// new 关键字 通过类实例化一个对象
let vNode = new Hello().render();
// 调用方式2:组件标签调用方式
vNode = <Hello/>
ReactDOM.render(vNode,document.getElementById("root"))
</script>
</body>
类组件的传参
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>类组件传参</title>
</head>
<body>
<div id="root"></div>
<script src="/babel.min.js"></script>
<script src="/react.development.js"></script>
<script src="/react-dom.development.js"></script>
<script type="text/babel">
class HelloName extends React.Component{
// react组件父类把props进行处理
// 方法中使用可以通过this.props调用
render(){
return <h1>hello,{this.props.name}</h1>
}
}
// JS语法调用
let vNode = new HelloName({name:'类组件'}).render()
// 组件标签方式调用
vNode = <HelloName name="class component"/>
// 复用
vNode = (
<div>
{new HelloName({name:'类组件1'}).render()}
{new HelloName({name:'类组件2'}).render()}
{new HelloName({name:'类组件3'}).render()}
<HelloName name="class1 component"/>
<HelloName name="class2 component"/>
</div>
)
ReactDOM.render(vNode,document.getElementById("root"))
</script>
</body>
# 事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JSX语法</title>
</head>
<body>
<div id="root"></div>
<script src="/babel.min.js"></script>
<script src="/react.development.js"></script>
<script src="/react-dom.development.js"></script>
<script type="text/babel">
class App extends React.Component{
// 事件处理方法
show(){
alert('你点击到我了!')
}
// 返回一个标签
showName(){
return <h1>hello react</h1>
}
render(){
return (
<div>
{/*调用显示标签 方法调用要立即执行 方法如果不需要立即调用就不需要写()*/}
{this.showName()}
{/*JSX语法里的主食*/}
{/*事件触发的方法不需要加(),加括号就立即触发了,这里点击事件触发后,再调用方法*/}
<button onClick={this.show}>点击显示</button>
</div>
)
}
}
ReactDOM.render(<App/>,document.getElementById("root"))
</script>
</body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>事件触发后this的指向</title>
</head>
<body>
<div id="root"></div>
<script src="/babel.min.js"></script>
<script src="/react.development.js"></script>
<script src="/react-dom.development.js"></script>
<script type="text/babel">
class App extends React.Component{
// 类属性 类变量
name = "hello,react"
show(){
// alert('show1触发了')
// this.属性名称 调用属性
/*
*事件触发后this指向谁?
*默认情况指向window
*严格模式下指向undefined
*React默认是严格模式
*this指向保持 怎么做?
*解决方案:绑定this操作
*bind 只绑定
*apply,call 绑定之后会调用方法
*this
* this就是组件对象
*/
console.log(this);
console.log(this.name);
console.log();
}
render(){
return (
<div>
{/*方法一:定义的是普通函数 bind绑定this*/}
<button onClick={this.show.bind(this)}>点击显示1</button>
{/*方法二:定义的是箭头函数 this指向不丢失*/}
<button onClick={this.show2}>点击显示2</button>
{/*方法三 事件触发的普通方法this丢失*/}
{/*事件触发箭头函数this指向正常*/}
<button onClick={()=>this.show()}>点击显示3</button>
</div>
)
}
// 一个作用域快写的方法都是平级的
// 箭头函数定义的方法 this的指向保持不丢失
show2=()=>{
console.log(this.name);
}
}
ReactDOM.render(<App/>,document.getElementById("root"))
</script>
</body>
# React 脚手架
node 环境
node -v
关于 node 版本 一般是根据公司的项目版本安装对应的版本
npm 命令
npm 仓库源地址
#检查地址
npm config get registry
#修改为国内镜像源
npm config set registry http://registry.npm.taobao.org/
# 生成项目包
npx 临时安装包软件的相关依赖命令 使用完毕之后删除
create-react-app react 脚手架
reactpro 项目包的名称 自定义
需要再哪儿生成项目 下载以下的命令即可
npx create-react-app reactpro
以上命令执行完毕之后
cd reactpro
npm start
访问流程:
- 浏览器中输入
localhost:3000
localhost 本地域名 3000 服务占用的端口 - react 脚手架启动 3000 端口服务
- react 启动的服务默认访问的就是 public 目录下
- 在
index.html
中找到<div id="root"></div>
挂在点 - webpack 运行在自动打包
index.js
和index.html
里 - src/index.js 引入了 src
# 状态:
React
// rcc快捷方式
/**
* Vue 组件的数据存放在data 数据自动监听的 当数据发生改变会自动刷新DOM 如果数据很多 会创建大量的监听器 性能就会低一些
* React 需要的时候再去刷新DOM 没有自动监听器
* React 提供了两个方法操作组件的状态
* State 获取数据
* setState 设置修改数据 刷新DOM
* 微信小程序借鉴了React数据管理
*/
import React, { Component } from "react";
export default class App extends Component {
// state初始化
state = { num: 1 };
// +1方法
doAdd() {
// 修改state的数据
// sst快捷提示
this.setState({ num: this.state.num + 1 });
}
render() {
return (
<div>
<h1>{this.state.num}</h1>
<button onClick={this.doAdd.bind(this)}>点击这里</button>
</div>
);
}
}
# setState
import React, { Component } from "react";
export default class App extends Component {
// 普通成员属性
num = 1;
// 事件处理方法 num+1
doAdd = () => {
this.num++;
console.log(this.num);
// 使用setState刷新DOM值必须写入{}
this.setState({});
};
render() {
return (
<div>
<h1>{this.num}</h1>
<button onClick={this.doAdd}>点击加1</button>
</div>
);
}
}
# setState 具有异步性
import React, { Component } from "react";
export default class App extends Component {
// 存储成state属性还是使用普通类成员
// 如果状态不需要渲染到DOM上,使用普通类成员属性
// 如果状态频繁发生改变需要修改渲染DOM 使用state
doChange() {
// sst快捷方式
// setState参数结构(参数1,参数2)
// 参数1:需要修改的state的数据 对象格式
// 参数2:回调方法 当DOM渲染完毕之后调用
// setState 修改state属性操作 是异步的 非阻塞 提高性能
// 如果业务操作中 有需求是需要修改state状态后操作的 这个操作就是需要卸载回调方法中
this.setState({ num: 100 }, () => {
console.log("页面渲染完毕num:", this.state.num);
});
// 修改后打印state值
console.log("num:", this.state.num);
}
state = { num: 1 };
render() {
return (
<div>
{/**这里的方法调用加() */}
{/**事件触发的方法 当事件触发时 在调用不加() */}
{/* <button onClick={this.doChange}>点击这里</button> */}
{/* 箭头函数触发 事件触发箭头函数 箭头函数要立即调用普通函数方法 */}
<button onClick={() => this.doChange()}>点击这里</button>
</div>
);
}
}
# 样式使用
标签属性 style 行内样式
属性 class
/**
* style 行内样式
*/
import React, { Component } from "react";
import "./assets/App.css";
export default class App extends Component {
size = 18;
// 练习:写一个按钮点击之后字体变大
// 分析:1.编写一个按钮并绑定点击事件
// 2.事件处理方法里 对size属性+1
// 3.刷新DOM
doChange() {
this.size++;
// 刷新DOM渲染页面
this.setState({});
}
render() {
return (
<div>
{/* JS描述样式的方式 */}
<div style={{ color: "red", fontSize: this.size }}>Hello React</div>
<button onClick={this.doChange.bind(this)}>点击放大字体</button>
<div className="danger">WEB2108</div>
{/* 动态改变绑定的样式class 根据size变量 */}
{/* <22 success 否则就是danger */}
<div className={this.size < 22 ? "success" : "danger"}>WEB2108</div>
{/* <22 sucess; 22-25 warn;>25 danger */}
{/* 如果再属性中写JS代码比较多的时,建议封装为方法 */}
{/* 只有事件触发的方法 调用不加() */}
<div className={this.showClass()}>WEB2108</div>
</div>
);
}
showClass() {
// <22 success;22-25 warn; >25danger>
if (this.size < 22) return "success";
if (this.size > 25) return "danger";
return "warn";
}
}
# 图片加载
import React, { Component } from 'react'
import mypng from './assets/1.jpg'
export default class App extends Component {
render() {
return (
<div>
{/* 远程地址 直接填写图片地址即可 */}
<img src="https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png" alt="" />
{/* 本地图片 习惯放在/src/assets目录下 */}
{/* 方法一 使用require语法 .default后缀 现在版本可以不用写 */}
<img src={require("./assets/1.jpg")} alt="" />
{/* 方法二 import mypng时引入的别名变量名称 */}
<img src={mypng} alt="" />
</div>
)
}
}
# 条件渲染
import React, { Component } from 'react'
import './assets/App.css'
export default class App extends Component {
score = 60
// delta 时表示变量的意思
changeScore(delta){
// 修改分数
// this.score = this.score+delta;
this.score +=delta
// 刷新DOM
this.setState({})
}
render() {
return (
<div>
<h4>当前分数为:{this.score}</h4>
<button onClick={this.changeScore.bind(this,-10)} disabled={this.score<=0}>-10分</button>
<button onClick={this.changeScore.bind(this,10)} disabled={this.score>=100}>+10分</button>
{/* 如果分数大于等于60 则显示及格了 否则显示不及格 */}
{this.show()}
</div>
)
}
show(){
if(this.score >=60){
// 返回JSX语法 不要加引号 加了引号返回的就是字符串了
return <div className='success'>及格</div>
}
else{
return <div className='danger'>不及格</div>
}
}
}
# 双向绑定
在表单元素中
单项流数据:数据渲染到页面 DOM 上
双向流数据:既满足单向流数据,又可以接收到用户输入的信息
数据和页面时双向的
数据<=>页面
vue 双向绑定
v-model
本质就是 v-bind v-on 结合的语法糖
import React, { Component } from 'react'
export default class App extends Component {
state = {name:'皮卡丘'}
_nameChange(e){
// e.target.value 文本框输入的值
console.log(e.target.value);
let name = e.target.value
this.setState({name})
}
render() {
// es6结构语法 后续调用为了更加方便一些
const {name} = this.state
return (
<div>
<input type="text" value={name} onChange={this._nameChange.bind(this)}/>
</div>
)
}
}