REACT(二)
核心内容
组件& Props
- 概念:
React
应用是由被称为组件
的独立UI
片段构建而成。React
组件本质上是可以任意添加标签的JavaScript
函数。组件可以小到一个按钮,也可以大到是整个页面。
// Profile.js
export default function Profile() {
return <img src="https://i.imgur.com/QIrZWGIs.jpg" alt="Alan L. Hart" />;
}
// Gallery.js
import Profile from "./Profile.js";
export default function Gallery() {
return (
<section>
<h1>Amazing scientists</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}
-
纯函数组件
- 纯函数
- 概念:即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。
- 必要条件:
- 纯函数接受参数,基于参数计算,返回一个新对象;
- 不会产生副作用,计算过程不会修改输入的参数并且不修改其作用域之外的参数或方法;
- 相同的输入保证相同的输出
- 优点:
- 相同的输入必定是相同的输出,所以纯函数可以根据输入来做缓存,此外这一特性保证了引用的透明性;
- 纯函数完全自给自足,这点的好处就是纯函数的依赖很明确,因此更易于观察和理解,而且让我们的测试更加容易;
- 可靠:不用担心有副作用,可以更好的工作;
- 代码并行:可以并行运行任意纯函数,因为纯函数不需要访问共享的内存,而且也不会因为副作用而进入竞争态。
- 例子:
let friend = { firstName: "zhang", lastName: "san", age: 18, }; // 非纯函数:会修改函数外变量 friend 的值 function appendMessage() { friend.message = { time: "2021年", info: "学习React", }; } // 纯函数:返回一个新对象,且不会修改参数 function appendMessage(friend) { let copyFriend = Object.assign({}, friend); copyFriend.message = { time: "2021年", info: "学习React", }; return copyFriend; }
- 概念:如果一个组件没有状态(
state
),那么组件的输出方式,将完全取决于两个参数:props
和context
,只要有相同的props
和context
,那么他们的输出绝对是相同的。将组件比喻成函数的话,相同的输入(props
和context
) 永远都会有相同的输出。 - 特点:
- 组件不会被实例化,整体渲染性能得到提升;
- 组件不能访问
this
对象; - 组件无法访问生命周期的方法;
- 无状态组件只能访问输入的 props,无副作用。
- 优点:
- 无副作用;
- 占内存更小,首次
render
的性能更好; - 语法更简洁,可读性好,逻辑简单,测试简单,代码量少,容易复用;
- 更佳的性能表现:因为函数组件中不需要进行生命周期的管理和状态管理,因此
React
并不需要进行某些特定的检查和内存分配,保证了性能。
- 缺点:
- 无生命周期;
- 没有
this
。
- 例子:
// es6 类组件 class Title extends React.Component { render() { return <h1>{this.props.title}</h1>; } }
- 纯函数
-
state
- 概念:
state
是组件对象最重要的属性,值是对象(可以包含多个key-value
的组合) - 注意事项
- 组件中
render
方法中的this
为组件实例对象; - 组件自定义的方法中
this
为undefined
,如何解决?- 强制绑定
this
: 通过函数对象的bind()
; - 箭头函数;
- 强制绑定
- 切勿直接修改
state
数据,直接state
会重新渲染内容; - 使用
setState
通过this.setState
修改完数据后,并不会立即修改DOM
里面的内容,react
会在这个函数内部的所有设置状态改变后,统一对比虚拟 DOM 对象,然后在统一修改,提升性能。
- 组件中
- 概念:
-
props
-
理解
- 每个组件对象都会有 props(properties 的简写)属性;
- 组件标签的所有属性都保存在 props 中;
-
作用
- 通过标签属性从组件外向组件内传递变化的数据;
- 组件内部不要修改
props
数据,props
永远是只读的。
-
-
refs
与事件处理
-
理解
- 组件内的标签可以定义
ref
属性来标识自己
- 组件内的标签可以定义
-
三种组件标签获取方式:
- 1、字符串形式的
ref
- 2、回调形式的
ref
- 3、
createRef
创建ref容器
- 1、字符串形式的
-
注意: 组件名称必须以大写字母开头。
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,代表 HTML 的 div 标签,而 则代表一个组件,并且需在作用域内使用 Welcome。
生命周期
-
1、初始化阶段: 由
ReactDOM.render
触发,该阶段的函数只执行一次。-
constructor
:构造函数,最先被执行,我们通常在构造函数里初始化 state 对象或者给自定义方法绑定 this。- 获取
props
和初始化state
- 通过
constructor
的参数props
获取 - 设置
state
和props
- 获取
-
getDerivedStateFromProps
:static getDerivedStateFromProps(nextProps, prevState)
,接收父组件传递过来的props
和组件之前的状态,返回一个对象来更新state
或者返回null
来表示接收到的props
没有变化,不需要更新state
。- 作用: 将父组件传递过来的
props
映射到子组件的state
上面,这样组件内部就不用再通过this.props.xxx
获取属性值了,统一通过this.state.xxx
获取。映射就相当于拷贝了一份父组件传过来的props
,作为子组件自己的状态。注意:子组件通过setState
更新自身状态时,不会改变父组件的props
; - 配合
componentDidUpdate
,可以覆盖componentWillReceiveProps
的所有用法; - 注意:
getDerivedStateFromProps
前面要加上static
保留字,声明为静态方法,不然会被react
忽略掉;getDerivedStateFromProps
里面的this
为undefined
。
- 作用: 将父组件传递过来的
-
render
:render
函数是纯函数,只返回需要渲染的东西,不应该包含其他的业务逻辑,可以返回原生的DOM
、React 组件
、Fragment
、Portals
、字符串
和数字
、Boolean
和null
等内容。- 作用:渲染组件到页面中,无法获取页面中的
DOM对象
- 注意:不要在
render
方法中调用setState()
方法,否则会递归渲染- 原因说明:状态改变会重新调用
render()
,render()
又重新改变状态
- 原因说明:状态改变会重新调用
- 作用:渲染组件到页面中,无法获取页面中的
-
componentDidMount
:组件状态之后调用,此时我们可以获取到DOM
节点并操作,比如对canvas
、svg
的操作,服务器请求,订阅都可以写在这里,但是记得要在componentWillunMount
中取消订阅。- 1、组件已经挂载到页面中
- 2、可以进行
DOM
操作,比如:获取到组件内部的DOM对象
- 3、可以发送请求获取数据
- 4、可以通过
setState()
修改状态的值 - 注意:在这里修改状态会重新渲染
-
-
2、更新阶段: 由组件内部
this.setSate
或父组件重新render
触发,该阶段的函数执行多次,每当组件的 props 或者 state 改变的时候,都会触发运行阶段的函数-
getDerivedStateFromProps
:此方法在更新挂在阶段都可能回调用。 -
shouldComponentUpdate
:shouldComponentUpdate(nextProps, nextState)
有两个参数nextProps
和nextState
, 标识更新的属性和变化之后的state
, 返回一个布尔值,true
标识会触发重新渲染,false
标识不会触发重新渲染,默认返回true
, 我们通常利用此声明周期来优化React
程序性能。- 作用:根据这个方法的返回值决定是否重新渲染组件,返回 true 重新渲染,否则不渲染
- 优势:通过某个条件渲染组件,降低组件渲染频率,提升组件性能
- 说明:如果返回值为 false,那么,后续 render()方法不会被调用
- 注意:这个方法必须返回布尔值!!!
- 场景:根据随机数决定是否渲染组件
-
render
:更新阶段也会触发此生命周期。- 作用:重新渲染组件,与 Mounting 阶段的 render 是同一个函数
- 注意:这个函数能够执行多次,只要组件的属性或状态改变了,这个方法就会重新执行
-
getSnapshotBeforeUpdate
:getSnapshotBeforeUpdate(prevProps, prevState)
这个方法在render
之后,componentDidUpdate
之前调用,有两个参数prevProps
和prevState
,标识之前的属性和之前的state
, 这个函数有一个返回值,会作为第三个参数传给componentDidUpdate
,如果不想要返回值, 可以返回null
, 此生命周期必须与componentDidUpdate
搭配使用。 -
componentDidUpdate
:componentDidUpdate(prevProps, prevState, snapshot)
,该方法在getSnapshotBeforeUpdate
方法之后被调用,有三个参数prevProps
、prevState
、snapshot
,表示之前的props
,之前的state
,和snapshot
。第三个参数是getSnapshotBeforeUpdate
返回的,如果触发某些回调函数时需要用到DOM
元素的状态,则将对比或计算的过程迁移至getSnapshotBeforeUpdate
,然后在componentDidUpdate
中统一触发回调或更新状态。- 作用:组件将要更新
- 参数:最新的属性和状态对象
- 注意:不能修改状态 否则会循环渲染
-
-
3、卸载组件: 由
ReactDOM.unmountComponentAtNode
触发componentWillUnmount
:会在组件卸载以及销毁之前调用,在此方法中执行必要的清理操作,例如,清除定时器,取消网络请求或者清除在componentDidMount()
中创建的订阅,清理无效的 DOM 元素等垃圾清理工作。
-
4、异常处理
static getDerivedStateFromError
: 此声明周期会在渲染阶段后代组件抛出错误后被调用,他将抛出的错误作为参数,并返回一个值以更新state
componentDidCatch
: 此生命周期在后代组件抛出错误后背调用,他接受两个参数:error
—— 抛出的错误;info
—— 带有componentStack key
的对象,其中包含有关组件引发错误的栈信息。componentDidCatch
会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况。
在新版本中也可以用旧的生命周期,但会警告提示甚至报错:
所以对于这三个钩子:componentWillMount
、componentWillUpdate
、componentWillReceiveProps
需要加上UNSAFE_
前缀才行