React是用于构建用户界面的JavaScript
库。
现在前端领域最为流行的三大框架:
其中,Vue和React是国内最为流行的两个框架。
React的特点:
1、声明式编程:它允许我们只需要维护自己的状态,当状态改变时,React可以根据最新的状态去渲染我们的UI界面。
2、组件化开发
3、多平台适配
React开发依赖
开发React必须依赖三个库:
如何添加这三个依赖?
方式一:直接CDN引入
方式二:下载后,添加本地依赖
方式三:通过npm
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin>script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin>script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js">script>
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>Hello React!title>
head>
<body>
<div id="app">div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin>script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin>script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js">script>
<script type="text/babel">
let msg = "Hello World!";
function btnClick() {
msg = "Hello React!";
render();
console.log("按钮发生了点击");
}
function render() {
ReactDOM.render(
<div>
<h2>{msg}</h2>
<button onClick={btnClick}>改变文本</button>
</div>,
document.getElementById("app"));
}
render();
script>
body>
html>
组件化
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>Hello React!title>
head>
<body>
<div id="app">div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin>script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin>script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js">script>
<script type="text/babel">
// 封装组件
class App extends React.Component {
constructor() {
super();
// this.msg = "Hello World!";
this.state = {
msg: "Hello World!"
}
}
render() {
return (
<div>
<h2>{this.state.msg}</h2>
<button onClick={this.btnClick.bind(this)}>改变文本</button>
</div>
)
}
btnClick() {
// this.msg = "Hello React!";
this.setState({
msg: "Hello React!"
})
console.log("按钮发生了点击");
}
}
// 渲染组件
ReactDOM.render(<App/>, document.getElementById("app"));
script>
body>
html>
ES6中如何定义类
<script>
// ES6中如何定义类
class Person {
// 构造方法
constructor(name, age) {
this.name = name;
this.age = age;
}
// 定义方法
running() {
console.log(this.name, "running...");
}
}
const p = new Person("Tom", 18);
console.log(p.name, p.age);
p.running();
script>
ES6中类的继承
<script>
// 面向对象的三大特性:封装、继承、多态
// 继承:1、减少重复代码 2、多态的前提
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
running() {
console.log(this.name, "running...");
}
}
class Student extends Person {
constructor(name, age, sno) {
super(name, age);
this.sno = sno;
}
}
const stu = new Student("Tom", 20, "110");
console.log(stu.name, stu.age, stu.sno);
stu.running();
class Teacher extends Person {
constructor(name, age, tno) {
// 子类中是必须初始化父类对象
super(name, age);
this.tno = tno;
}
}
const t = new Teacher("Sam", 44, "000");
console.log(t.name, t.age, t.tno);
t.running();
script>
电影列表展示
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="app">div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin>script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin>script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js">script>
<script type="text/babel">
class App extends React.Component {
constructor() {
super();
this.state = {
movies: ["大话西游", "盗梦空间", "战狼", "流浪地球", "星际穿越"]
}
}
render() {
let result = []
for (let movie of this.state.movies) {
result.push(<li>{movie}</li>);
}
return (
<div>
<h2>电影列表1</h2>
<ul>{result}</ul>
<h2>电影列表2</h2>
<ul>{
this.state.movies.map((item) => {
return <li>{item}</li>
})
}</ul>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
script>
body>
html>
计数器
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="app">div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin>script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin>script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js">script>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
cnt: 0
}
}
render() {
return (
<div>
<h2>当前计数:{this.state.cnt}</h2>
<button onClick={this.increment.bind(this)}>+1</button>
<button onClick={this.decrement.bind(this)}>-1</button>
</div>
)
}
increment() {
console.log("+1");
this.setState({
cnt: this.state.cnt + 1
})
}
decrement() {
console.log("-1");
this.setState({
cnt: this.state.cnt - 1
})
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
script>
body>
html>
JSX是什么?
JSX是一种JavaScript的语法扩展,它用于描述我们的UI界面,并且其完全可以和JavaScript融合在一起使用。
React认为渲染逻辑本质上与其他UI逻辑存在内在耦合
它们之间是密不可分的,所以React没有将标记分离到不同的文件中,而是将它们组合到一起
JSX书写规范:
JSX顶层只能有一个根元素,所以我们很多时候会在外层包裹一个div
为了方便阅读,我们通常在jsx的外层包裹一个小括号(),这样阅读方便,并且JSX可以进行换行书写
JSX中的标签可以是单标签,也可以是双标签
注意:如果是单标签,必须以/>
结尾
JSX中的注释:{/* 我是注释 */}
JSX嵌入数据
1、在{}中可以正常显示的内容
String
Number
Array
2、在{}中不能显示(忽略)
null
undefined
Boolean
3、对象类型不能作为子元素
JSX嵌入表达式
1、运算符表达式
2、三元表达式
3、进行函数调用
JSX绑定属性
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: "标题",
imgUrl: "https://placekitten.com/200/300",
link: "https://www.baidu.com",
active: true
}
}
render() {
return (
<div>
<h1>Hello React!</h1>
{/* 1、绑定普通属性 */}
<h2 title={this.state.title}>我是标题</h2>
<img src={this.state.imgUrl} alt="kitten"/>
{/* 2、绑定class */}
<a href={this.state.link} target="_blank" className="box">百度一下</a>
<div className={"title " + (this.state.active ? "active" : "")}>我是div</div>
{/* 3、绑定style */}
<div style={{color: "red", fontSize: "24px"}}>我是div,绑定style属性</div>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
script>
JSX绑定事件
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: "您好",
movies: ["大话西游", "盗梦空间", "战狼", "流浪地球"]
}
// this.btnClick = this.btnClick.bind(this);
}
render() {
return (
<div>
<h1>Hello React!</h1>
{/* 方案一:bind绑定this(显示绑定) */}
{/* 方案二:定义函数时,使用箭头函数 */}
{/* 方案三:直接传入箭头函数,在箭头函数中调用要执行的函数 */}
<button onClick={this.btnClick.bind(this)}>按钮1</button>
<button onClick={() => { this.btnClick() }}>按钮2</button>
<ul>
{
this.state.movies.map((item, index, arr) => {
return <li onClick={e => { this.liClick(item, index, e) }}>{item}</li>
})
}
</ul>
</div>
)
}
btnClick() {
console.log("按钮被点击了...");
console.log(this.state.msg);
}
liClick(item, index, event) {
console.log("li被点击了...");
console.log(index, item);
console.log(event);
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
script>
条件渲染
在vue中,我们会通过指令来控制:比如v-if
、v-show
在react中,所有的条件判断都和普通JavaScript代码一致
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLogin: true
}
}
render() {
// 1、if判断(适用于逻辑代码非常多的情况)
let welcome = null;
if (this.state.isLogin) {
welcome = <h2>欢迎回来~</h2>
} else {
welcome = <h2>请先登录~</h2>
}
return (
<div>
<h1>Hello React!</h1>
{welcome}
{/* 2、使用三元运算符 */}
<button onClick={e => this.btnClick()}>{this.state.isLogin ? "退出" : "登录"}</button>
{/* 3、使用逻辑与 */}
{ this.state.isLogin && <h2>您好,admin</h2>}
</div>
)
}
btnClick() {
this.setState({
isLogin: !this.state.isLogin
})
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
script>
列表渲染
真实开发中,我们会从服务器请求到大量的数据,数据会以列表的形式存储。
<script type="text/babel">
class App extends React.Component {
constructor() {
super();
this.state = {
movies: ["大话西游", "盗梦空间", "战狼", "流浪地球", "星际穿越"]
}
}
render() {
let result = []
for (let movie of this.state.movies) {
result.push(<li>{movie}</li>);
}
return (
<div>
<h2>电影列表1</h2>
<ul>{result}</ul>
<h2>电影列表2</h2>
<ul>{
this.state.movies.map((item) => {
return <li>{item}</li>
})
}</ul>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
script>
JSX的本质:实际上,JSX仅仅只是React.createElement(component, props, … , children)函数的语法糖,所有的JSX最终都会被转换成React.createElement的函数调用。
JSX --> createElement函数 --> ReactElement(对象树)–> ReactDOM.render函数 --> 真实DOM
JSX --> createElement函数 --> ReactElement(对象树)–> ReactDOM.render 函数 --> 原生的控件
传统的脚手架指的是建筑学的一种结构:在搭建楼房、建筑物时,临时搭建出来的一个框架
编程中提到的脚手架,其实是一种工具,帮助我们快速生成项目的工程化结构
总结:脚手架让项目从搭建到开发,再到部署,整个流程变得快速和便捷
它们的作用都是帮助我们生成一个通用的目录结构,并且已经将我们所需的工程环境配置好。
安装脚手架
npm install -g create-react-app
创建React项目
create-react-app 项目名称
注意:项目名称不能包含大写字母
启动项目
cd 项目目录
yarn start
分而治之的思想
分而治之是软件工程的重要思想,是复杂系统开发和维护的基石
而前端目前的模块化和组件化都是基于分而治之的思想
什么是组件化开发?
我们需要通过组件化的思想来思考整个应用程序:
我们将一个完整的页面分成很多个组件
每个组件都用于实现页面的一个功能块
而每一个组件又可以进行细分
而组件本身又可以在多个地方进行复用
组件化是React的核心思想
组件化思想的应用:
类组件
类组件的定义有如下要求:
组件的定义方式
// 类组件的定义
export default class App extends React.Component {
constructor() {
super();
this.state = {
msg: "您好,App组件"
}
}
render() {
return (
我是App组件
{this.state.msg}
)
}
}
// 函数组件的定义
export default function App() {
return (
我是函数组件
)
}
// 特点:
// 1、没有this对象
// 2、没有内部的状态(可以使用hooks解决)
render函数的返回值:
生命周期
很多事物都有从创建到销毁的整个过程,这个过程称之为生命周期
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5c4xbNPE-1676984826440)(assets/image-20211122165735596.png)]
生命周期是一个抽象概念,在生命周期的整个过程中,分成了很多个阶段:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gc4zOiEY-1676984826441)(assets/image-20211122165812449.png)]
React内部为了告诉我们当前处于哪些阶段,会对我们组件内部实现某些函数进行回调,这些函数就是生命周期函数。
import React, { Component } from 'react'
class Component1 extends Component {
render() {
return (
我是Component1组件
)
}
componentWillUnmount() {
console.log("调用了Component1的componentWillUnmount方法");
}
}
export default class App extends Component {
constructor() {
super();
this.state = {
cnt: 0,
isShow: true
}
console.log("执行了组件的constructor方法");
}
render() {
console.log("执行了组件的render方法");
return (
我是App组件
当前计数:{this.state.cnt}
{this.state.isShow && }
)
}
increment() {
this.setState({
cnt: this.state.cnt + 1
})
}
changeComponent1Show() {
this.setState({
isShow: !this.state.isShow
})
}
componentDidMount() {
console.log("执行了组件的componentDidMount方法");
}
componentDidUpdate() {
console.log("执行了组件的componentDidUpdate方法");
}
}
constructor中通常只做两件事情:
1、通过给this.state赋值对象来初始化内部state
2、为事件绑定实例(this)
componentDidMount
componentDidUpdate
componentWillUnmount
组件嵌套
import React, { Component } from 'react'
// Header
function Header() {
return 我是Header组件
}
// Main
function Main() {
return (
我是Main组件
)
}
// Banner
function Banner() {
return 我是Banner组件
}
// 商品列表
function ProductList() {
return (
- 商品1
- 商品2
- 商品3
- 商品4
- 商品5
)
}
// Footer
function Footer() {
return 我是Footer组件
}
export default class App extends Component {
render() {
return (
)
}
}
组件之间的通信
父传子-函数组件
import React, { Component } from 'react'
function Child(props) {
const { name, age } = props;
return {name + " " + age}
}
export default class App extends Component {
render() {
return (
)
}
}
父传子-类组件
import React, { Component } from 'react'
class Child extends Component {
render() {
const { name, age } = this.props;
return (
子组件展示的数据:{name + " " + age}
)
}
}
export default class App extends Component {
render() {
return (
)
}
}
属性验证
import React, { Component } from 'react'
import PropTypes from 'prop-types'
function Child(props) {
const { name, age, names } = props;
return (
{name + "--" + age}
{
names.map((item, index) => {
return - {index + "-" + item}
})
}
)
}
Child.protoTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
names: PropTypes.array
}
Child.defaultProps = {
name: "test",
age: 67,
names: ["x", "y", "z"]
}
export default class App extends Component {
render() {
return (
)
}
}
在某些情况下,我们也需要子组件向父组件传递消息:
子传父通信
import React, { Component } from 'react'
class CntButton extends Component {
render() {
const { increment } = this.props;
return (
)
}
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
cnt: 0
}
}
render() {
return (
当前计数:{this.state.cnt}
{this.increment()}} />
)
}
increment() {
this.setState({
cnt: this.state.cnt + 1
})
}
}
组件通信案例练习
import React, { Component } from 'react'
import TabControl from './TabControl'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
currentTitle: "新款",
titles: ['新款', '精选', '流行']
}
}
render() {
const { currentTitle, titles } = this.state;
return (
this.itemClick(index)} titles={titles} />
{currentTitle}
)
}
itemClick(index) {
console.log(index);
this.setState({
currentTitle: this.state.titles[index]
})
}
}
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class TabControl extends Component {
constructor(props) {
super(props);
this.state = {
currentIndex: 0
}
}
render() {
const { titles } = this.props;
const { currentIndex } = this.state;
return (
{
titles.map((item, index) => {
return this.itemClick(index)}>{item}
})
}
)
}
itemClick(index) {
this.setState({
currentIndex: index
})
const { itemClick } = this.props;
itemClick(index);
}
}
TabControl.propTypes = {
titles: PropTypes.array.isRequired
}
效果展示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KTOrEN2u-1676984826441)(assets/image-20211122215853733.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PlvvMps0-1676984826441)(assets/image-20211122215907659.png)]
React实现插槽slot
import React, { Component } from 'react'
import NavBar from './NavBar'
import NavBar2 from './NavBar2'
export default class App extends Component {
render() {
return (
)
}
}
import React, { Component } from 'react'
export default class NavBar extends Component {
render() {
return (
{this.props.children[0]}
{this.props.children[1]}
{this.props.children[2]}
)
}
}
import React, { Component } from 'react'
export default class NavBar extends Component {
render() {
const { leftSlot, centerSlot, rightSlot } = this.props;
return (
{leftSlot}
{centerSlot}
{rightSlot}
)
}
}
跨组件通信
方式一:通过props属性自上而下(由父到子)进行传递
import React, { Component } from 'react'
function ProfileHeader(props) {
return (
用户昵称:{props.nickname}
用户等级:{props.level}
)
}
function Profile(props) {
return (
- 设置1
- 设置2
- 设置3
- 设置4
)
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
nickname: "tom",
level: 100
}
}
render() {
const { nickname, level } = this.state;
return (
)
}
}
方式二:使用Context
import React, { Component } from 'react'
// 创建Context对象
const UserContext = React.createContext({
nickname: "test",
level: 0
})
function ProfileHeader() {
return (
{
value => {
return (
用户昵称:{value.nickname}
用户等级:{value.level}
)
}
}
)
}
function Profile() {
return (
- 设置1
- 设置2
- 设置3
- 设置4
)
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
nickname: "tom",
level: 100
}
}
render() {
return (
)
}
}
在组件化中选择合适的CSS解决方案应该符合以下条件:
常见的方式:
1、内联样式
内联样式是官方推荐的一种CSS样式写法
style接受一个采用小驼峰命名属性的JavaScript对象,而不是CSS字符串
并且可以引用state中的状态来设置相关样式
import React, { PureComponent } from 'react'
export default class App extends PureComponent {
render() {
const pStyle = {
color: "orange",
textDecoration: "underline"
}
return (
我是标题
我是一段文字描述
)
}
}
优点:
缺点:
2、普通CSS
我们通常会将CSS编写到单独的文件中,之后再进行引入。
这样的编写方式和普通的网页开发中编写方式是一样的,但是普通的CSS都属于全局的CSS,样式之间会相互影响。
这种编写方式最大的问题是样式之间会相互层叠掉。
3、CSS Modules
CSS Modules并不是React特有的解决方案,而是所有使用了类似webpack配置的环境下都可以使用的。
React的脚手架已经内置了CSS Modules的配置。
CSS Modules确实解决了局部作用域的问题,也是很多人喜欢在React中使用的一种方案。
但是这种方案也有自己的缺陷:
4、CSS-in-JS
CSS-in-JS是指一种模式,其中CSS由JavaScript生成而不是在外部文件中定义。
目前比较流行的CSS-in-JS的库有哪些?
安装styled-components
yarn add styled-components
styled-components
AntDesign
是基于 Ant Design 设计体系的React UI组件库,主要用于研发企业级中后台产品。
Ant Design - 一套企业级 UI 设计语言和 React 组件库
安装AntDesign
yarn add antd
介绍 - Ant Design (gitee.io)
Ant Design of React - Ant Design (gitee.io)
组件总览 - Ant Design (gitee.io)
资源 - Ant Design (gitee.io)
Axios 中文文档 | Axios 中文网 (axios-http.cn)
axios是目前前端使用非常广泛的网络请求库
安装
yarn add axios
起步 | Axios 中文文档 (axios-http.cn)
请求方法:
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
请求配置
这些是创建请求时可以用的配置选项。只有url
是必需的,如果没有指定method
,请求将默认使用GET
方法。
{
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // 默认值
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 它只能用与 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData,或 Stream
// 你可以修改请求头。
transformRequest: [function (data, headers) {
// 对发送的 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对接收的 data 进行任意转换处理
return data;
}],
// 自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是与请求一起发送的 URL 参数
// 必须是一个简单对象或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer`是可选方法,主要用于序列化`params`
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作为请求体被发送的数据
// 仅适用 'PUT', 'POST', 'DELETE 和 'PATCH' 请求方法
// 在没有设置 `transformRequest` 时,则必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属: FormData, File, Blob
// - Node 专属: Stream, Buffer
data: {
firstName: 'Fred'
},
// 发送请求体数据的可选语法
// 请求方式 post
// 只有 value 会被发送,key 则不会
data: 'Country=Brasil&City=Belo Horizonte',
// `timeout` 指定请求超时的毫秒数。
// 如果请求时间超过 `timeout` 的值,则请求会被中断
timeout: 1000, // 默认值是 `0` (永不超时)
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // default
// `adapter` 允许自定义处理请求,这使测试更加容易。
// 返回一个 promise 并提供一个有效的响应 (参见 lib/adapters/README.md)。
adapter: function (config) {
/* ... */
},
// `auth` HTTP Basic Auth
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 表示浏览器将要响应的数据类型
// 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
// 浏览器专属:'blob'
responseType: 'json', // 默认值
// `responseEncoding` 表示用于解码响应的编码 (Node.js 专属)
// 注意:忽略 `responseType` 的值为 'stream',或者是客户端请求
// Note: Ignored for `responseType` of 'stream' or client-side requests
responseEncoding: 'utf8', // 默认值
// `xsrfCookieName` 是 xsrf token 的值,被用作 cookie 的名称
xsrfCookieName: 'XSRF-TOKEN', // 默认值
// `xsrfHeaderName` 是带有 xsrf token 值的http 请求头名称
xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值
// `onUploadProgress` 允许为上传处理进度事件
// 浏览器专属
onUploadProgress: function (progressEvent) {
// 处理原生进度事件
},
// `onDownloadProgress` 允许为下载处理进度事件
// 浏览器专属
onDownloadProgress: function (progressEvent) {
// 处理原生进度事件
},
// `maxContentLength` 定义了node.js中允许的HTTP响应内容的最大字节数
maxContentLength: 2000,
// `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
maxBodyLength: 2000,
// `validateStatus` 定义了对于给定的 HTTP状态码是 resolve 还是 reject promise。
// 如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),
// 则promise 将会 resolved,否则是 rejected。
validateStatus: function (status) {
return status >= 200 && status < 300; // 默认值
},
// `maxRedirects` 定义了在node.js中要遵循的最大重定向数。
// 如果设置为0,则不会进行重定向
maxRedirects: 5, // 默认值
// `socketPath` 定义了在node.js中使用的UNIX套接字。
// e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。
// 只能指定 `socketPath` 或 `proxy` 。
// 若都指定,这使用 `socketPath` 。
socketPath: null, // default
// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
// and https requests, respectively, in node.js. This allows options to be added like
// `keepAlive` that are not enabled by default.
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// `proxy` 定义了代理服务器的主机名,端口和协议。
// 您可以使用常规的`http_proxy` 和 `https_proxy` 环境变量。
// 使用 `false` 可以禁用代理功能,同时环境变量也会被忽略。
// `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据。
// 这将设置一个 `Proxy-Authorization` 请求头,它会覆盖 `headers` 中已存在的自定义 `Proxy-Authorization` 请求头。
// 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// see https://axios-http.com/docs/cancellation
cancelToken: new CancelToken(function (cancel) {
}),
// `decompress` indicates whether or not the response body should be decompressed
// automatically. If set to `true` will also remove the 'content-encoding' header
// from the responses objects of all decompressed responses
// - Node only (XHR cannot turn off decompression)
decompress: true // 默认值
}
响应结构
一个请求的响应包含以下信息。
{
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 是服务器响应头
// 所有的 header 名称都是小写,而且可以使用方括号语法访问
// 例如: `response.headers['content-type']`
headers: {},
// `config` 是 `axios` 请求的配置信息
config: {},
// `request` 是生成此响应的请求
// 在node.js中它是最后一个ClientRequest实例 (in redirects),
// 在浏览器中则是 XMLHttpRequest 实例
request: {}
}
默认配置
axios.defaults.baseURL = "https://httpbin.org"
axios.defaults.timeout = 5000
axios.defaults.headers.common["token"] = "token"
拦截器
// 拦截器
axios.interceptors.request.use(config => {
// 1. 发送请求时,页面显示loading
// 2. 添加token
// 3. 序列化操作
// 4. ……
return config;
}, err => {
console.log(err);
return err;
});
axios.interceptors.response.use(res => {
return res.data;
}, err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
console.log("400");
break;
case 401:
console.log("401");
break;
default:
console.log("其他错误")
break;
}
}
return err;
});
React中的状态管理方式:
Redux就是一个帮助我们管理State
的容器。
Redux是JavaScript的状态容器,提供了可预测的状态管理。
三大原则:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PQ4dUH9J-1676984826442)(assets/image-20211204093348972.png)]
基本使用
// 导入redux
const redux = require('redux');
const initialState = {
counter: 0
}
// reducer
function reducer(state = initialState, action) {
switch(action.type) {
case "INCREMENT":
return {...state, counter: state.counter + 1};
case "DECREMENT":
return {...state, counter: state.counter - 1};
case "ADD_NUMBER":
return {...state, counter: state.counter + action.num};
case "SUB_NUMBER":
return {...state, counter: state.counter - action.num};
default:
return state;
}
}
// store
const store = redux.createStore(reducer);
// actions
const action1 = {type: 'INCREMENT'};
const action2 = {type: 'DECREMENT'};
const action3 = {type: 'ADD_NUMBER', num: 5};
const action4 = {type: 'SUB_NUMBER', num: 12};
// 订阅store修改
store.subscribe(() => {
console.log("counter:", store.getState().counter);
});
// 派发action
store.dispatch(action1);
store.dispatch(action2);
store.dispatch(action3);
store.dispatch(action4);
Redux使用流程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jvYvIpuI-1676984826442)(assets/image-20211202220226503.png)]
官方文档:
React Redux | React Redux (react-redux.js.org)
前端流行的三大框架都有自己的路由实现:
React Router的版本从4开始,路由不再集中在一个包中进行管理了
安装react-router
yarn add react-router-dom
Router的基本使用
import React, { PureComponent } from 'react'
import {
BrowserRouter,
Link,
Route,
Routes
} from 'react-router-dom';
import Home from './pages/home';
import About from './pages/about';
export default class App extends PureComponent {
render() {
return (
首页
关于
} />
} />
)
}
}
文档:React Router | Docs Home (reactrouterdotcom.fly.dev)
Hook 是 React 16.8 的新增特性。它可以让你在不编写class的情况下使用state以及其他的React特性。
Hook 简介 – React (docschina.org)
useState的基本使用
import React, { useState } from 'react';
export default function Counter() {
/**
* Hook: useState
* 本身是一个函数,来自react包
* 参数:作用是给创建出来的状态一个默认值
* 返回值:数组,元素1:当前state的值;元素2:设置新的值时,使用的函数
*/
const [state, setState] = useState(0);
return (
当前计数:{state}
)
}
两个额外的规则:
复杂状态的操作
export default function MultiHookState() {
const [count, setCount] = useState(0);
const [age, setAge] = useState(18);
const [friends, setFriends] = useState(["小明", "小狗", "小虎"]);
const [students, setStudents] = useState([
{id: 110, name: "学生1", age: 10},
{id: 111, name: "学生2", age: 18},
{id: 112, name: "学生3", age: 30},
]);
function incrementAgeByIndex(index) {
const newStudents = [...students];
newStudents[index].age += 1;
setStudents(newStudents);
}
return (
当前计数:{count}
我的年龄:{age}
好友列表:
{
friends.map((item, index) => {
return - {item}
})
}
学生列表:
序号
姓名
年龄
操作
{
students.map((item, index) => {
return (
{index+1}
{item.name}
{item.age}
)
})
}
)
}
useEffect的基本使用
import React, { useEffect, useState } from 'react'
export default function ChangeCounterTitle() {
const [cnt, setCnt] = useState(0);
useEffect(() => {
document.title = `计数器:${cnt}`
});
return (
计数器:{cnt}
)
}
useContext的基本使用
import React, { useContext } from 'react';
import {UserContext, ThemeContext} from '../App';
export default function ContextHookDemo() {
const user = useContext(UserContext);
const theme = useContext(ThemeContext);
console.log(user);
console.log(theme);
return (
ContextHookDemo
)
}
useRef返回一个ref对象,返回的ref对象在组件的整个生命周期保持不变。
两种最常用的ref:
Hook API 索引 – React (docschina.org)