草庐IT

快速体验React开发基础入门指南

CoderBin 2023-03-28 原文

前言

大家好,我是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 = Hello React // 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 = ( <span>Hello React</span> ) ReactDOM.render(VDOM,document.getElementById('app')) </script> </body> 拓展:使用 jsx 创建的DOM最终会被转成 React element 元素,我们一般直接使用 jsx 即可

三、jsx 的基础学习

1. 基本认识

  1. jsx 全称:JavaScript XML
  2. react定义的一种类似于XML的JS扩展语法: JS + XML本质是React.createElement(component, props, ...children)方法的语法糖
  3. 作用: 用来简化创建虚拟DOM
  • 写法:const VDOM = Hello JSX!
  • 注意1:它不是字符串, 也不是HTML/XML标签
  • 注意2:它最终产生的就是一个JS对象

2. jsx 语法规则

  1. 虚拟DOM必须只有一个根标签
  2. 定义虚拟DOM时,不要写引号
  3. 标签中混入js表达式,或者凡是想动态指定id、class、style,标签内容时,要使用大括号 {}
  4. 样式的类型指定要使用 className,为了避开js里面的关键字class
  5. label 标签的 for 属性要写成 htmlFor
  6. 内联样式:要用 style={{color:'blue',fontSize:'30px'}} 的形式去写
  7. 标签必须闭合
  8. 关于标签首字母
  • 若小写字母开头,则将标签转为html中同名元素,若html中无该标签对应的同名元素,则报错
  • 若大写字母开头,react会去渲染对应的组件,若组件未定义,则报错
<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中显示 参数说明

  • 参数一: 纯 js 或 jsx 创建的虚拟 dom 对象
  • 参数二: 用来包含虚拟 DOM 元素的真实 dom 元素对象(一般是一个div)

五、使用脚手架创建项目

1. 创建项目

create-react-app Hello 注意:需要提前全局安装 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. 自定义编写流程

  1. 其中,最重要的是 src 目录下的 index.js 和 App.js 文件

    • App.js 是程序的根组件,建议其他组件都作为该组件的子组件
    • index.js 是程序的入口文件,主要编写挂载 App 组件的代码
  2. 主要关注的是 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. 函数式组件

创建函数式组建的注意事项:

  1. 函数名首字母必须大写

  2. 函数必须要有 return

  3. 使用 ReactDOM.render() 时,必须写成标签形式

  4. 注意:经过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() 之后,发生了什么?

  1. React解析组件标签,找到对应组件
  2. 发现组件时函数式定义的,随后调用该函数
  3. 将返回的虚拟DOM转为真实DOM,随后呈现在页面中

2. 类式组件

创建类式组件的注意事项:

  1. 类名首字母必须大写
  2. 使用类创建组件,必须继承 React.Component 父类
  3. 类中必须要实现 render 方法,并且有 return
  4. HTML标签首字母要小写,组件首字母要大写
  5. 使用 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()之后,发生了什么?

  1. React解析组件标签,找到对应组件
  2. 发现组件时类式定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法
  3. 将返回的虚拟DOM转为真实DOM,随后呈现在页面中

六、React 事件绑定的方式

1. 通过onXxx属性指定事件处理函数(注意大小写)

  • React 使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —— 为了更好的兼容性
  • React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素) —— 更高效
2. 通过event.target得到发生事件的DOM元素对象 —— 不要过度使用 ref

3. 具体实现:

3.1 在类式组件中绑定事件,React 推荐使用行内形式,例如:

<button onClick={this.handleClick}>点击</button> 3.2 然后在类中自定义回调函数,要用赋值语句的形式 + 箭头函数。说明:

  • 使用赋值的写法,这个方法就放在了实例自身;
  • 由于使用了箭头函数,其内部的this指向就是外层作用域下的this(组件的实例对象,这样可以拿到实例上的属性值)
<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 的三种方案

  • 方案一: bind 绑定 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 理解

  1. state 是组件实例上已经定义好的一个属性,初始值为 null
  2. state 是组件对象最重要的属性, 值是 对象 (可以包含多个 key-value 的组合)
  3. 组件被称为 "状态机", 通过更新组件的 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 {this.state.msg} } } 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 {this.state.msg} } } ReactDOM.render(<Component/>, document.getElementById('app')) </script> </body> 强烈注意

  1. 组件中render方法中的this为组件实例对象
  2. 组件自定义的方法中this为undefined,如何解决?
  • 强制绑定this: 通过函数对象的bind(),,但是必须写在构造器中,这种写法不方便
this.changeWeather = this.changeWeather.bind(this)
  • 推荐使用的方式:赋值语句的形式 + 箭头函数
  1. 状态数据,不能直接修改或更新,需要用到 setState

2. props - 组件通信-父传子

2.1 理解

  1. 每个组件对象都会有 props (properties的简写) 属性
  2. 组件标签的所有属性都保存在 props 中
  3. props 是只读的,不可修改
2.2 作用

  1. 通过标签属性从组件外向组件内传递变化的数据
  2. 注意: 组件内部不要修改 props 数据
2.3 简单使用

  1. 第一种写法:将属性值直接写在组件标签上,
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 获取属性值

  • const { name, age } = 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 进行限制

  1. 直接在类中添加 static 静态属性即可,必须使用 propTypes

  2. 给传递的属性定义具体规则时,必须使用 PropTypes ,具体写法看下面示例

  3. 如果想要指定属性值的默认值,必须使用 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

  1. react会收集添加了 ref 属性的元素
  2. 通过 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="点击按钮弹出数据"/>&nbsp; <button onClick={this.clickShowData}>点击弹出左边的数据</button> </div> ) } } ReactDOM.render(<Demo/>, document.getElementById('app')) </script> </body> 3.2 回调函数形式的 ref

  1. ref 为回调函数的形式,react 内部会调用定义的回调函数
<input ref={c=>this.input1=c} type="text" /> 回调函数里的含义是:把 ref 所在的节点挂载到组件的实例 this上,名字为 input1 2. 直接从组件实例 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="点击按钮弹出数据"/>&nbsp; <button onClick={this.clickShowData}>点击弹出左边的数据</button> </div> ) } } ReactDOM.render(<Demo/>, document.getElementById('app')) </script> </body> 3.3 createRef 的形式

  1. 使用 React.createRef() 的形式获取 DOM 元素,(直接把 inputRef 绑定到 组件实例 this上,直接 this.inputRef.current 可以获取)
  2. createRef 调用后会返回一个容器,该容器可以存储被 ref 所标识的 DOM 元素,该容器是 "独一无二的"
  3. 这也是 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="点击按钮弹出数据"/>&nbsp; <button onClick={this.clickShowData}>点击弹出左边的数据</button>&nbsp; </div> ) } } ReactDOM.render(<Demo/>, document.getElementById('app')) </script> </body> 3.4 总结

  • 一般用回调形式的 ref 就行了,比 ``React.createRef() 方便
  • 拓展:jsx 中注释的写法:{/* <div>哈哈哈</div> */}

八、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 中展示

九、高阶函数-函数柯里化

  1. 高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数
  • 若A函数,接收的参数是一个函数,那么A就可以称为高阶函数
  • 若A函数,调用之后的返回值依然是一个函数,那么A就可以称为高阶函数
  1. 函数的柯里化:通过函数调用继续返回函数的方法,实现多次接收参数最后统一处理的函数编码形式
使用函数柯里化的形式,可以优化一些回调函数的写法,比如上面代码中的非受控组件,不同的 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> 说明

  • 在给两个 input 的 change 事件定义的回调函数是同一个,区别是各自传入了不同的参数

  • 在回调函数中,又返回了一个函数,给 onChange 调用。在返回的函数中就根据传入的参数,将数据存储在 state 中对应的属性身上

十. React 组件的生命周期(重点)

1. 组件的生命周期(旧)

  • 先上张图压压惊

生命周期的三个阶段(旧)

  1. 初始化阶段: 由 ReactDOM.render() 触发---初次渲染
  • constructor() — 初始化参数
  • componentWillMount() — 组件将要挂载
  • render() - 组件渲染
  • componentDidMount() — 组件挂载完毕(常用,一般做初始化的事:发送请求等)
  1. 更新阶段: 由组件内部 this.setSate() 或父组件重新 render 触发
  • shouldComponentUpdate() — 控制组件 state 更新的 "阀门",组件是否应该更新 return true|false
  • componentWillUpdate() — 组件将要更新
  • render() — 组件渲染
  • componentDidUpdate() — 组件更新完毕
  1. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
  • componentWillUnmount() — 组件将要卸载(常用,一般用于收尾操作)
补充:componentWillReciveProps — 组件将要接收新的 props。注意,这里只有第二次接收才算...

2. 组件的生命周期(新)

  • 先上张图压压惊
生命周期的三个阶段(新)

  1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
  • constructor()
  • getDerivedStateFromProps — 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。
  • render()
  • componentDidMount()
  1. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
  • getDerivedStateFromProps
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate — 在最近一次渲染输出(提交到 DOM 节点)之前调用
  • componentDidUpdate()
  1. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
  • componentWillUnmount()

3. 将要废弃的生命周期函数

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate
注意:现在使用会出现警告,下一个大版本需要加上 UNSAFE_ 前缀才能使用,以后可能会被彻底废弃,不建议使用。

十一、DOM 的 diff算法

1. 经典面试题:

  1. react/vue中的key有什么作用?(key的内部原理是什么?)
  2. 为什么遍历列表时,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) // 值为订阅时的返回值 }
每文一句:世界上三种东西最宝贵——知识、粮食和友谊。

本次的分享就到这里,如果本章内容对你有所帮助的话欢迎点赞+收藏。文章有不对的地方欢迎指出,有任何疑问都可以在评论区留言。希望大家都能够有所收获,大家一起探讨、进步!

有关快速体验React开发基础入门指南的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  3. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  4. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  5. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  8. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  9. 软件测试基础 - 2

    Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功

  10. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

随机推荐