React函数类组件及其Hooks学习
- 函数类组件
- 函数式组件和类式组件的区别:
- 为什么要使用函数式组件?
- Hooks概念及常用的Hooks
- 1.
useState
: State的Hook- 语法
- useState()说明:
- setXxx()2种写法:
- 示例
- 2.
useEffect
: 副作用的Hook- React中的副作用操作
- 语法和说明:
- 总体说明:
- 替代
componentDidMount
: - 替代
componentDidUpdate
: - 替代
componentWillUnmount
:
- 实例:
- 3.
useRef
: ref的Hook- 语法:
- 实例:
- 1.
- 函数类组件中使用props
函数类组件
函数式组件和类式组件的区别:
React组件可以分为类组件和函数式组件,两者最明显的不同就是在语法上,函数组件是一个纯函数,它接收一个props对象返回一个react元素。而类组件需要去继承React.Component并且创建render函数返回react元素,这将会要更多的代码,虽然它们实现的效果相同。
- 函数式组件中没有state
- 函数式组件中没有生命周期(重点,涉及到生命周期的方法只能在类组件中定义。)
在较新的react版本看中添加了hooks,使得我们可以在函数组件中使用useState钩子去管理state,使用useEffect钩子去使用生命周期函数。从这个改版中我们可以看出作者更加看重函数组件,而且react团队曾提及到在react之后的版本将会对函数组件的性能方面进行提升。
为什么要使用函数式组件?
- Hooks是比高阶组件(HOC)和render props更优雅的逻辑复用方式。这个是很多人喊“真香”的原因。优雅的逻辑复用方式,会促进一个更加蓬勃的生态,这对于原本生态就很强的React来说是如虎添翼。会有更多的人愿意把自己的逻辑抽离成hooks(因为真的太优雅了),发布为library,为react生态添砖加瓦(看看这段时间各种基于hooks的状态管理工具)。我还认为,很快会出现一些“hooks生态圈”的“lodash”。
- 函数式组件的心智模型更加“声明式”。hooks(主要是useEffect)取代了生命周期的概念(减少API),让开发者的代码更加“声明化”:
- 旧的思维:“我在这个生命周期要检查props.A和state.B(props和state),如果改变的话就触发xxx副作用”。这种思维在后续修改逻辑的时候很容易漏掉检查项,造成bug。
- 新的思维:“我的组件有xxx这个副作用,这个副作用依赖的数据是props.A和state.B”。从过去的命令式转变成了声明式编程。
- 其实仔细想一想,人们过去使用生命周期不就是为了判断执行副作用的时机吗?现在hooks直接给你一个声明副作用的API,使得生命周期变成了一个“底层概念”,无需开发者考虑。开发者工作在更高的抽象层次上了。
- 类似的道理,除了声明副作用的API,react还提供了声明“密集计算”的API(useMemo),取代了过去“在生命周期做dirty检查,将计算结果缓存在state里”的做法。React内核帮你维护缓存,你只需要声明数据的计算逻辑以及数据的依赖。
- 函数式组件的心智模型更加“函数式”。react团队正在循序渐进地教育社区,为未来的并发模式打下基础。(其实react从一开始就受到了很多函数式编程的影响,现在推行函数式组件算是“回归初心”)。下面我会详细讨论函数式组件的心智模型。
Hooks概念及常用的Hooks
Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。
React官网是这样描述Hooks的:Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据),而并非强制按照生命周期划分。你还可以使用 reducer 来管理组件的内部状态,使其更加可预测。
1. useState
: State的Hook
State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作。
语法
const [xxx, setXxx] = React.useState(initValue)
useState()说明:
参数: 第一次初始化指定的值在内部作缓存;
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数。
可以多次使用useState()
。
setXxx()2种写法:
setXxx(newValue)
: 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue)
: 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
示例
import React, { useState } from 'react';
function Example() {
// 声明一个叫 “count” 的 state 变量。
const [count, setCount] = useState(0);
// 加的回调 setXxx()第二种写法
function add() {
setCount(count => count + 1);
}
return (
You clicked {count} times
);
}
export default Example
2. useEffect
: 副作用的Hook
Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)。
我们之前可能已经在React组件中执行过数据获取、订阅或者手动修改过DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。它跟 class 组件中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的用途,只不过被合并成了一个 API。
React中的副作用操作
- 发ajax请求数据获取
- 设置订阅 / 启动定时器
- 手动更改真实DOM
语法和说明:
- 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作
- 将
useEffect
放在组件内部让我们可以在 effect 中直接访问count
state 变量(或其他 props)。 - 默认情况下,它在第一次渲染之后和每次更新之后都会执行,即不加第二个参数的情况下。
总体说明:
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
可以多次使用useEffect
。
替代componentDidMount
:
useEffect(() => {
// 在此可以执行任何带副作用操作,来初始化代码
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
替代componentDidUpdate
:
useEffect(() => {
// 在此可以执行任何带副作用操作
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行,此时不能为空,数组内的值为所监控的state的值,如果不加此参数,默认为所有的state的值
// 例如如下代码
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
替代componentWillUnmount
:
useEffect(() => {
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
})
实例:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
You clicked {count} times
);
}
3. useRef
: ref的Hook
Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据,跟React.createRef()
类似。
useRef
返回一个可变的 ref 对象,其 .current
属性被初始化为传入的参数(initialValue
)。返回的 ref 对象在组件的整个生命周期内保持不变。
语法:
const refContainer = useRef()
ref 对象的 .current
属性为相应的 DOM 节点。
实例:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
);
}
函数类组件中使用props
使用方式类似类组件的props使用,父级组件需要暴露接口给子组件,子组件才能接收,子组件接收数据的方法:直接作为函数的参数(props)传给子组件。
import React, { useState } from 'react'
import Title from "../Title"
//父级组件传过去
function Parent() {
let [count, setCount] = useState(1)
const add = (count) => { setCount(count) }
return (
//类似类组件中的接口传递数据到子组件
<button onClick={() => add(count + 1)}>+</button>
</div>)
}
export default Parent;
//子组件接收
import React from 'react'
function Title(props) {
return (
<h1>{props.count}</h1>
)
}
export default Title;
</code></pre>
</div>
<!--conend-->
<div class="p-2"></div>
<div class="arcinfo my-3 fs-7 text-center">
<a href='/t/etagid89-0.html' class='tagbtn' target='_blank'>react</a><a href='/t/etagid16119-0.html' class='tagbtn' target='_blank'>hooks</a>
</div>
<div class="p-2"></div>
</div>
<div class="p-2"></div>
<!--xg-->
<div class="lbox p-4 shadow-sm rounded-3">
<div class="boxtitle"><h2 class="fs-4">相关</h2></div>
<hr>
<div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-564770.html">react dom移动算法</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-562681.html">React组件重构:嵌套+继承 与 高阶组件</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-562967.html">React中嵌套组件与被嵌套组件的通信</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-561843.html">AntDesign(React)学习-15 组件定义、connect、interface</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-556539.html">初学ReactJS,写了一个RadioButtonList组件</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-554177.html">快速搭建react项目骨架(按需加载、redux、axios、项目级目录等等)</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-554505.html">react传值名称使用value可能出现死循环</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-543897.html">React Native bind函数</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-543802.html">React Native constructor方法内外this的区别</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-543176.html">使用 create-react-app 创建基于 ts 项目</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-541705.html">react源码解析17.context</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div><div class="row g-0 py-2 border-bottom align-items-center">
<div class="col-7 col-lg-11 border-lg-end">
<h3 class="fs-6 mb-0 mb-lg-2"><a href="/a/1-541381.html">react源码解析14.手写hooks</a></h3>
<div class="ltag fs-8 d-none d-lg-block">
</div>
</div>
</div>
<!---->
<!---->
</div>
<!--xgend-->
</div>
<div class="col-lg-3 col-12 p-0 ps-lg-2">
<!--box-->
<!--boxend-->
<!--<div class="p-2"></div>-->
<!--box-->
<div class="lbox p-4 shadow-sm rounded-3">
<div class="boxtitle pb-2"><h2 class="fs-4"><a href="#">标签</a></h2></div>
<div class="clearfix"></div>
<ul class="m-0 p-0 fs-7 r-tag">
</ul>
<div class="clearfix"></div>
</div>
<!--box end-->
</div>
</div>
</div>
</main>
<div class="p-2"></div>
<footer>
<div class="container-fluid p-0 bg-black">
<div class="container p-0 fs-8">
<p class="text-center m-0 py-2 text-white-50">一品网 <a class="text-white-50" href="https://beian.miit.gov.cn/" target="_blank">冀ICP备14022925号-6</a></p>
</div>
</div>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?6e3dd49b5f14d985cc4c6bdb9248f52b";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</footer>
<script src="/skin/bootstrap.bundle.js"></script>
</body>
</html>