前言
大家好,我是 CoderBin,本次整理了我学习 react 过程中的各部分的知识点,看完文本你将会学到
jsx 的基本使用
使用脚手架创建项目
如何在 React 当中定义组件
React 当中的事件绑定方式以及注意事项
关于 react 组件的三大核心属性及其运用
React 组件的生命周期
...
如果文中有不对、疑惑的地方,欢迎在评论区留言指正🌻
想深入学习的可以前往 React官网
关于 React 当中的路由(router)、状态管理(redux),使用技巧可以点击下面链接前往学习
React 专栏
【1】React-Router 5 快速上手指南!
【2】React-Router6 全面解析 🔥🔥🔥
【3】Redux+React-Redux 最新入门实战指南💥
【4】关于React,这几个常用技巧你应该知道!
一、React 初体验
步骤:准备一个容器、创建虚拟 DOM、使用 ReactDOM.render()
方法渲染页面
注意:如果在 html 页面中使用 React,需要导入三个包。其中,react.development.js
必须在react-dom.development.js
之前引入,下面为了方便,便不再引入。
<head>
<!-- 注意: 部署时,将 "development.js" 替换为 "production.min.js"。-->
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
</head>
<body>
<!-- 准备一个容器 -->
<div id="app"></div>
<!-- 注意:此处必须写babel -->
<script type="text/babel">
// 1. 创建虚拟DOM
const VDOM = <h1>Hello React</h1>
// 2. 渲染虚拟DOM到页面(虚拟DOM, 容器)
ReactDOM.render(VDOM,document.getElementById('app'))
</script>
</body>
复制代码
注意:上面都是在一个 html 文件里面编写 react,为了方便 jsx 的部分会在这里说明,其他的会在脚手架创建的项目中说明
二、虚拟 DOM 的两种创建方式
1. 使用纯 js 创建
<body>
<div id="app"></div>
<script type="text/javascript">
// 使用纯js创建虚拟DOM太繁琐,可读性差,不利于维护
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello React'));
ReactDOM.render(VDOM,document.getElementById('app'))
</script>
</body>
复制代码
2. 使用 jsx 创建
<body>
<!-- 准备一个容器 -->
<div id="app"></div>
<script type="text/babel">
// 使用 jsx 创建虚拟DOM便捷高效
const VDOM = (
<h1 id="h1">
<span>Hello React</span>
</h1>
)
ReactDOM.render(VDOM,document.getElementById('app'))
</script>
</body>
复制代码
拓展:使用 jsx 创建的 DOM 最终会被转成 React element 元素,我们一般直接使用 jsx 即可
三、jsx 的基础学习
1. 基本认识
jsx 全称:JavaScript XML
react 定义的一种类似于 XML 的 JS 扩展语法: JS + XML 本质是 React.createElement(component, props, ...children)方法的语法糖
作用: 用来简化创建虚拟 DOM
2. jsx 语法规则
虚拟 DOM 必须只有一个根标签
定义虚拟 DOM 时,不要写引号
标签中混入 js 表达式,或者凡是想动态指定 id、class、style,标签内容时,要使用大括号 {}4. 样式的类型指定要使用 className,为了避开 js 里面的关键字 class5. label 标签的 for 属性要写成 htmlFor
6. 内联样式:要用 style={{color:'blue',fontSize:'30px'}}
的形式去写
标签必须闭合
关于标签首字母
<body>
<div id="app"></div>
<script type="text/babel">
const myId = 'aTgUiGu'
const myData = 'Hello React'
const VDOM = (
<div>
<h2 id={myId.toLowerCase()} className="title">
<span style={{color:'blue',fontSize:'30px'}}>{myData.toLowerCase()}</span>
</h2>
<input type='text'/>
<!--能运行,但会报错,因为html并没有这个标签-->
<good>123</good>
</div>
)
ReactDOM.render(VDOM, document.getElementById('app'));
</script>
</body>
复制代码
四、渲染虚拟 DOM
语法:ReactDOM.render(virtualDOM, containerDOM)
作用: 将虚拟 DOM 元素渲染到页面中的真实容器 DOM 中显示参数说明
五、使用脚手架创建项目
1. 创建项目
注意:需要提前全局安装 react 的脚手架 npm i -g create-react-app
2. 项目结构文件
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库的支持)
复制代码
3. 自定义编写流程
其中,最重要的是 src 目录下的 index.js 和 App.js 文件
App.js 是程序的根组件,建议其他组件都作为该组件的子组件
index.js 是程序的入口文件,主要编写挂载 App 组件的代码
主要关注的是 index.js 的入口文件该如何编写,由于 React17 和 React18 版本的写法有些许不同,以下列出各自的写法
React17
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App/>, document.getElementById('root'))
复制代码
React18
import { createRoot } from "react-dom/client";
import App from './App'
const root = createRoot(document.getElementById('root'))
root.render(<App/>)
复制代码
六、React 中定义组件的两种方式
1. 函数式组件
创建函数式组建的注意事项:
函数名首字母必须大写
函数必须要有 return
使用 ReactDOM.render()
时,必须写成标签形式
注意:经过 babel 编译(开启严格)后的函数,禁止了内部的 this 指向 window
<body>
<div id="app"></div>
<script type="text/babel">
// 创建函数式组件
function MyComponent() {
console.log(this); // undefined
return (
<h2>我是用函数定义的组件(使用于【简单组件】的定义)</h2>
)
}
ReactDOM.render(<MyComponent/>, document.getElementById('app'))
</script>
</body>
复制代码
拓展:执行了 ReactDOM.render() 之后,发生了什么?
React 解析组件标签,找到对应组件
发现组件时函数式定义的,随后调用该函数
将返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中
2. 类式组件
创建类式组件的注意事项:
类名首字母必须大写
使用类创建组件,必须继承 React.Component 父类
类中必须要实现 render 方法,并且有 return
HTML 标签首字母要小写,组件首字母要大写
使用 ReactDOM.render() 时,必须写成标签形式
<body>
<div id="app"></div>
<script type="text/babel">
// 创建类式组件
class MyComponent extends React.Component {
render() {
// render中的this是谁? —— MyComponent的实例对象 <=> MyComponent组件实例对象
console.log('render中的this',this); // MyComponent{}
return <h2>我是用类定义的组件(使用于【复杂组件】的定义)</h2>
}
}
ReactDOM.render(<MyComponent/>, document.getElementById('app'))
</script>
</body>
复制代码
拓展: 执行了 ReactDOM.render()之后,发生了什么?
React 解析组件标签,找到对应组件
发现组件时类式定义的,随后 new 出来该类的实例,并通过该实例调用到原型上的 render 方法
将返回的虚拟 DOM 转为真实 DOM,随后呈现在页面中
六、React 事件绑定的方式
1. 通过 onXxx 属性指定事件处理函数(注意大小写)
2. 通过 event.target 得到发生事件的 DOM 元素对象 —— 不要过度使用 ref
3. 具体实现:
3.1 在类式组件中绑定事件,React 推荐使用行内形式,例如:
<button onClick={this.handleClick}>点击</button>
复制代码
3.2 然后在类中自定义回调函数,要用赋值语句的形式 + 箭头函数。说明:
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 失焦事件
blurShowData = (e) => {
// 这个 e 就是当前发生事件的 DOM 元素
console.log(e.target);
alert(e.target.value)
}
render() {
// React推荐使用行内形式
return (
<div>
<input onBlur={this.blurShowData} type="text" placeholder="表单失焦弹出数据"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
复制代码
4. 事件绑定中处理 this 的三种方案
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
message: "你好啊",
counter: 100
}
// bind绑定this
this.btnClick = this.btnClick.bind(this);
}
render() {
return (
<div>
{/* 1.方案一: bind绑定this(显示绑定) */}
<button onClick={this.btnClick}>按钮1</button>
<button onClick={this.btnClick}>按钮2</button>
<button onClick={this.btnClick}>按钮3</button>
{/* 2.方案二: 定义函数时, 使用箭头函数 */}
<button onClick={this.increment}>+1</button>
{/* 2.方案三(推荐): 直接传入一个箭头函数, 在箭头函数中调用需要执行的函数*/}
<button onClick={() => { this.decrement("why") }}>-1</button>
</div>
)
}
btnClick() {
console.log(this.state.message);
}
// increment() {
// console.log(this.state.counter);
// }
// 箭头函数中永远不绑定this
// ES6中给对象增加属性: class fields
increment = () => {
console.log(this.state.counter);
}
decrement(name) {
console.log(this.state.counter, name);
}
}
ReactDOM.render(<App/>, document.getElementById("app"));
</script>
复制代码
七、组件三大核心属性
1. state
1.1 理解
state 是组件实例上已经定义好的一个属性,初始值为 null
state 是组件对象最重要的属性, 值是 对象 (可以包含多个 key-value 的组合)
组件被称为 "状态机", 通过更新组件的 state 来更新对应的页面显示(重新渲染组件)
1.2 state 的简单使用
直接在组件类中,给 state 赋值一个对象,往里面添加属性值即可
<body>
<div id="app"></div>
<script type="text/babel">
class Component extends React.Component {
state = {
msg: 'hello state'
}
render() {
return <h1>{this.state.msg}</h1>
}
}
ReactDOM.render(<Component/>, document.getElementById('app'))
</script>
</body>
复制代码
1.3 如何修改 state 中的值
使用:必须调用 React 内置的 setState()
方法去修改 state 中的值,通过 this 调用即可
说明:该 setState 在父类的 React.component 类身上,使用 this 顺着原型链就能找到
<body>
<div id="app"></div>
<script type="text/babel">
class Component extends React.Component {
state = {
msg: 'hello state'
}
changeMsg = () => {
// 调用 setState 方法,更新数据
this.setState({
msg: 'hello React'
})
}
render() {
return <h1 onClick={this.changeMsg}>{this.state.msg}</h1>
}
}
ReactDOM.render(<Component/>, document.getElementById('app'))
</script>
</body>
复制代码
强烈注意:
组件中 render 方法中的 this 为组件实例对象
组件自定义的方法中 this 为 undefined,如何解决?
this.changeWeather = this.changeWeather.bind(this)
复制代码
状态数据,不能直接修改或更新,需要用到 setState
2. props - 组件通信-父传子
2.1 理解
每个组件对象都会有 props (properties 的简写) 属性
组件标签的所有属性都保存在 props 中
props 是只读的,不可修改
2.2 作用
通过标签属性从组件外向组件内传递变化的数据
注意: 组件内部不要修改 props 数据
2.3 简单使用
第一种写法:将属性值直接写在组件标签上,
ReactDOM.render(<Person name="张三" age={19}/>, document.getElementById('app'))
复制代码
注意:如果要传递 number 类型数据,必须使用{}2. 第二种写法:事先准备好一个数据对象,然后通过拓展运算符传递
const data = {name:"张三", age:19}
ReactDOM.render(<Person {...data}/>, document.getElementById('app'))
复制代码
注意:使用 this.props 获取数据时,属性名要与数据对象保持一致说明:正常情况下是无法对一个对象直接使用拓展运算符的,是因为 babel + react.development.js 的加持下,才允许这么写,仅可以在组件标签中这么写 3. 从组件实例 this 上的 props 获取属性值
<body>
<div id="app"></div>
<script type="text/babel">
class Person extends React.Component {
render() {
// props 会接收到组件标签上的属性值
const { name, age } = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
// 1. 将属性值只在写在组件标签上
// ReactDOM.render(<Person name="张三" age="19"/>, document.getElementById('app'))
// 2. 另一种写法,采用展开运算符
const data = {name:"张三", age:19}
ReactDOM.render(<Person {...data}/>, document.getElementById('app'))
</script>
</body>
复制代码
2.4 对 props 进行限制
直接在类中添加 static 静态属性即可,必须使用 propTypes
给传递的属性定义具体规则时,必须使用 PropTypes ,具体写法看下面示例
如果想要指定属性值的默认值,必须使用 defaultProps
<body>
<div id="app"></div>
<div id="app1"></div>
<div id="app2"></div>
<script type="text/babel">
class Person extends React.Component {
// 给 Person 添加静态属性,(给类自身添加属性)
static propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
sex: PropTypes.string,
speak:PropTypes.func,
}
// 指定默认值
static defaultProps = {
age: 18,
sex: '未知'
}
render() {
const { name, age, sex } = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>年龄:{age}</li>
<li>性别:{sex}</li>
</ul>
)
}
}
ReactDOM.render(<Person name="小明" age={19} sex="男"/>, document.getElementById('app'))
ReactDOM.render(<Person name="小红" sex="女"/>, document.getElementById('app1'))
ReactDOM.render(<Person name="小强" age={34}/>, document.getElementById('app2'))
</script>
</body>
复制代码
注意:如果在 html 页面对 props 进行限制,必须导入 prop-types.js
这个包
2.5 在函数式组件使用 props
<body>
<div id="app"></div>
<script type="text/babel">
// 接收 props,即可拿到标签属性的值
function Person(props) {
return (
<ul>
<li>姓名:{props.name}</li>
<li>年龄:{props.age}</li>
</ul>
)
}
// 函数式组件对props的值进行限制,只能通过这种方式
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
}
Person.defaultProps = {
age: 18,
}
ReactDOM.render(<Person name="jack"/>, document.getElementById('app'))
</script>
</body>
复制代码
3.子传父
核心原理:父组件传递一个函数给子组件,子组件接收这个函数,调用时传递参数,父组件就能接收到参数。
4. refs
理解:组件内的标签可以定义 ref 属性来标识自己
3.1 字符串形式的 ref
react 会收集添加了 ref 属性的元素
通过 this.refs 就可拿到对应 ref 属性值的元素
注意:React 官方不推荐字符串这种形式的写法,“因为 string 类型的 refs 存在 一些问题。它已过时并可能会在未来的版本被移除。”
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 点击事件
clickShowData = () => {
// 通过 this.refs 就可拿到对应 ref 属性值的元素
const { input1 } = this.refs
alert(input1.value)
}
render() {
// 1. react会收集添加了 ref 属性的元素
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮弹出数据"/>
<button onClick={this.clickShowData}>点击弹出左边的数据</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
复制代码
3.2 回调函数形式的 ref
ref 为回调函数的形式,react 内部会调用定义的回调函数
<input ref={c=>this.input1=c} type="text" />
复制代码
回调函数里的含义是:把 ref 所在的节点挂载到组件的实例 this 上,名字为 input12. 直接从组件实例 this 即可拿到节点元素
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 点击事件
clickShowData = () => {
// 2. 直接从组件实例 this 拿到节点元素
const { input1 } = this
alert(input1.value)
}
render() {
// 1. ref 为回调函数的形式,react 内部会调用
// 回调函数里的含义是:把 ref 所在的节点挂载到组件的实例 this上,名字为 input1
return (
<div>
<input ref={c=>this.input1=c} type="text" placeholder="点击按钮弹出数据"/>
<button onClick={this.clickShowData}>点击弹出左边的数据</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
复制代码
3.3 createRef 的形式
使用 React.createRef()
的形式获取 DOM 元素,(直接把 inputRef 绑定到 组件实例 this 上,直接 this.inputRef.current
可以获取)
createRef 调用后会返回一个容器,该容器可以存储被 ref 所标识的 DOM 元素,该容器是 "独一无二的"
这也是 React 官方推荐的形式
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 使用 React.createRef() 的形式获取 DOM 元素
inputRef = React.createRef()
// 点击事件
clickShowData = () => {
// 2. 直接从组件实例 this 拿到节点元素
console.log(this);
const input = this.inputRef.current;
alert(input.value)
}
render() {
return (
<div>
<input ref={this.inputRef} type="text" placeholder="点击按钮弹出数据"/>
<button onClick={this.clickShowData}>点击弹出左边的数据</button>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
复制代码
3.4 总结
八、React 中收集表单数据
1. 非受控组件
理解:表单中所有输入类的组件,现用现取的就是非受控组件
<body>
<div id="app"></div>
<script type="text/babel">
class Login extends React.Component {
// 展示输入数据
showData = (e) => {
e.preventDefault() // 阻止表单提交
const {username, password} = this
alert(`用户名:${username.value},密码:${password.value}`)
}
render() {
return (
<form action="https://www.baidu.com" onSubmit={this.showData}>
用户名<input ref={c=>this.username=c} type="text" name="username"/><br/>
密码:<input ref={c=>this.password=c} type="password" name="password"/>
<button>提交</button>
</form>
)
}
}
ReactDOM.render(<Login/>, document.getElementById('app'))
</script>
</body>
复制代码
说明:这里其实是通过 ref 获取当前 DOM 元素,就可以拿到输入的 value 值
2. 受控组件
理解:表单中所有输入类的组件,将值存进 state 维护,后面再使用的就叫受控组件
<body>
<div id="app"></div>
<script type="text/babel">
class Login extends React.Component {
state = {
username: '',
password: ''
}
// 保存 username 到 state 中
saveUsername = (e) => {
this.setState({
username: e.target.value
})
}
// 保存 password 到 state 中
savePassword = (e) => {
this.setState({
password: e.target.value
})
}
// 展示输入数据
showData = (e) => {
e.preventDefault()
const { username, password } = this.state
alert(`用户名:${username},密码:${password}`)
}
render() {
return (
<form action="https://www.baidu.com" onSubmit={this.showData}>
用户名<input onChange={this.saveUsername} type="text" name="username"/><br/>
密码:<input onChange={this.savePassword} type="password" name="password"/>
<button>提交</button>
</form>
)
}
}
ReactDOM.render(<Login/>, document.getElementById('app'))
</script>
</body>
复制代码
说明:这里是监听了 input 的 change 事件,当内容发生变化,就会立即调用。然后会把最新值存入 state 中维护。
注意:这里的 change 事件分别写了两个函数,万一后面有更多的需要监听,会非常的繁琐。所以后面会使用 函数柯里化 进行优化。
3. 实现表单数据的双向绑定
<body>
<div id="app"></div>
<script type="text/babel">
class Demo extends React.Component {
// 存放用户输入的数据
state = {
msg: ''
}
// 监听input的change事件,将数据存入state中
saveMsg = (e) => {
this.setState({
msg: e.target.value
})
}
render() {
return (
<div>
<h2>实时显示你输入的数据:{this.state.msg}</h2>
<input onChange={this.saveMsg} type="text" placeholder="请输入"/>
</div>
)
}
}
ReactDOM.render(<Demo/>, document.getElementById('app'))
</script>
</body>
复制代码
说明:这里是监听了 input 的 change 事件,然后将最新的数据存入 state 中,然后在 jsx 中展示
九、高阶函数-函数柯里化
高阶函数:如果一个函数符合下面 2 个规范中的任何一个,那该函数就是高阶函数
函数的柯里化:通过函数调用继续返回函数的方法,实现多次接收参数最后统一处理的函数编码形式
使用函数柯里化的形式,可以优化一些回调函数的写法,比如上面代码中的非受控组件,不同的 input 元素定义一个不同的回调函数,当需要获取的数据项多了时,就会显得非常臃肿。此时,就可以函数柯里化就派上用场了,具体实现看如下实例:
<body>
<div id="app"></div>
<script type="text/babel">
class Login extends React.Component {
state = {
username: '',
password: ''
}
// 保存表单数据到 state 中,这里就是高阶函数,并且实现了函数的柯里化
saveFormData = (dataType) => {
// 返回一个函数,给事件去调用
// 当注册事件时,直接调用并参入参数,那么事件 e 就在 return 的函数参数里
return (e) => {
// 当接收一个变量作为对象的的键时,必须使用 []
this.setState({
[dataType]: e.target.value
})
}
}
// 展示输入数据
showData = (e) => {
e.preventDefault()
const { username, password } = this.state
alert(`用户名:${username},密码:${password}`)
}
render() {
return (
<form action="https://www.baidu.com" onSubmit={this.showData}>
用户名<input onChange={this.saveFormData('username')} type="text" name="username"/><br/>
密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
<button>提交</button>
</form>
)
}
}
ReactDOM.render(<Login/>, document.getElementById('app'))
</script>
</body>
复制代码
说明:
十. React 组件的生命周期(重点)
1. 组件的生命周期(旧)
生命周期的三个阶段(旧)
初始化阶段: 由 ReactDOM.render() 触发---初次渲染
更新阶段: 由组件内部 this.setSate() 或父组件重新 render 触发
shouldComponentUpdate() — 控制组件 state 更新的 "阀门",组件是否应该更新 return true|false
componentWillUpdate() — 组件将要更新
render() — 组件渲染
componentDidUpdate() — 组件更新完毕
卸载组件: 由 ReactDOM.unmountComponentAtNode()触发
补充:componentWillReciveProps — 组件将要接收新的 props。注意,这里只有第二次接收才算...
2. 组件的生命周期(新)
生命周期的三个阶段(新)
初始化阶段: 由 ReactDOM.render()触发---初次渲染
更新阶段: 由组件内部 this.setSate()或父组件重新 render 触发
卸载组件: 由 ReactDOM.unmountComponentAtNode()触发
3. 将要废弃的生命周期函数
componentWillMount
componentWillReceiveProps
componentWillUpdate
注意:现在使用会出现警告,下一个大版本需要加上 UNSAFE_ 前缀才能使用,以后可能会被彻底废弃,不建议使用。
十一、DOM 的 diff 算法
1. 经典面试题:
react/vue 中的 key 有什么作用?(key 的内部原理是什么?)
为什么遍历列表时,key 最好不要用 index?
2. 虚拟 DOM 中 key 的作用:
1). 简单的说: key 是虚拟 DOM 对象的标识, 在更新显示时 key 起着极其重要的作用。
2). 详细的说: 当状态中的数据发生变化时,react 会根据【新数据】生成【新的虚拟 DOM】,随后 React 进行【新虚拟 DOM】与【旧虚拟 DOM】的 diff 比较,比较规则如下:
a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
根据数据创建新的真实DOM,随后渲染到到页面
复制代码
3. 用 index 作为 key 可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作: 会产生没有必要的真实 DOM 更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的 DOM: 会产生错误 DOM 更新 ==> 界面有问题。
3. 注意! 如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用 index 作为 key 是没有问题的。
十三、消息订阅发布-组件通信-任意组件
1. 作用
适用于任意组件间的通信,这里使用 PubSub-js 第三方库实现订阅发布
2. 安装
yarn add pubsub-js
3. 使用
说明:以下伪代码在类式组件中运行
publish() 发布,用于发送数据,一般在某个事件的回调函数中使用
import PubSub from 'pubsub-js'
// PubSub.publish(发布名称, 数据)
PubSub.publish('coder', {name: 'bin', age: 21})
复制代码
subscribe() 订阅,用于接收数据,一般在 componentDidMount
生命周期函数中执行
import PubSub from 'pubsub-js'
// 要在组件挂载完后开始订阅
componentDidMount() {
// PubSub.subscribe(发布名称, 回调函数)
this.token = PubSub.subscribe('coder', (msg, data) =>{
console.logI(msg) // coder(这个msg没啥用,但必须写,否则报错,人家就这么设计)
console.log(data) // {name: 'bin', age: 21}
})
}
复制代码
unsubscribe(),用于取消订阅,谁订阅,谁取消,一般在 componentWillUnmount
生命周期中执行
// 组件将要卸载时,取消订阅
componentWillUnmount() {
PubSub.unsubscribe(this.token) // 值为订阅时的返回值
}
复制代码
往期推荐 💐 🌸 🌹 🌻 🌺 🍁
高阅读好文:
【1】关于Vue的一些高频面试题总结
【2】75道关于CSS的高频面试题总结,请注意查收!🔥
【3】Vue内置指令大全
【4】40道Promise输出题,你都会了吗?🔥
【5】js 和 css 是如何影响DOM树构建的?
----- 🌻 查看全部 🍁 -----
每文一句:世界上三种东西最宝贵——知识、粮食和友谊。
本次的分享就到这里,如果本章内容对你有所帮助的话欢迎点赞+收藏。文章有不对的地方欢迎指出,有任何疑问都可以在评论区留言。希望大家都能够有所收获,大家一起探讨、进步!
评论