React函数类组件及其Hooks学习
函数类组件
函数式组件和类式组件的区别:
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 (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me to + 1
</button>
<button onClick={() => setCount(add)}>
Click me to add 1
</button>
</div>
);
}
export default Example
2. useEffect: 副作用的Hook
Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)。
我们之前可能已经在React组件中执行过数据获取、订阅或者手动修改过DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
React中的副作用操作
- 发ajax请求数据获取
- 设置订阅 / 启动定时器
- 手动更改真实DOM
语法和说明:
- 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作
- 将
useEffect放在组件内部让我们可以在 effect 中直接访问countstate 变量(或其他 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 (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
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 (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
函数类组件中使用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 (<div>
//类似类组件中的接口传递数据到子组件
<Title count={count} />
<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;
React函数类组件及其Hooks学习的更多相关文章
- [React] 函数定义组件
函数定义组件的例子 function Welcome(props) { return <h1>Hello, {props.name}</h1>; } 该函数是一个有效的 Rea ...
- react hooks 如何自定义组件(react函数组件的封装)
前言 这里写一下如何封装可复用组件.首先技术栈 react hooks + props-type + jsx封装纯函数组件.类组件和typeScript在这不做讨论,大家别白跑一趟. 接下来会说一下封 ...
- React 函数组件中对window添加事件监听resize导致回调不能获得Hooks最新状态的问题解决思路
React 函数组件中对window添加事件监听resize导致回调不能获得Hooks最新状态的问题解决思路 这几天在忙着把自己做的项目中的类组件转化为功能相同的函数组件,首先先贴一份该组件类组件的关 ...
- React - 组件:类组件
目录: 1. 类组件有自己的状态 2. 继承React.Component-会有生命周期和this 3. 内部需要一个render函数(类组件会默认调用render方法,但不会默认添加,需要手动填写r ...
- React函数式组件和类组件[Dan]
一篇对Dan的 How Are Function Components Different from Classes? 一文的个人阅读总结,内容来自于此.强烈推荐阅读 Dan Abramov.的博客. ...
- 关于React采坑(憨批)系列---类组件(class MyCom extends React.Component--VM47:9 Uncaught TypeError: Super expression must either be null or a function, not undefined)
今天在学习React中的类组件时,突然给我报错VM47:9 Uncaught TypeError: Super expression must either be null or a function ...
- 【转】【Html】Vuejs2.0学习之二(Render函数,createElement,vm.$slots,函数化组件,模板编译,JSX)
1.Render函数 所以直接来到Render,本来也想跳过,发现后面的路由貌似跟它还有点关联.先来看看Render 1.1 官网一开始就看的挺懵的,不知道讲的是啥,动手试了一下,一开头讲的是Rend ...
- Vuejs2.0学习之二(Render函数,createElement,vm.$slots,函数化组件,模板编译,JSX)
时隔一周多,因为一些别的事情绊住了,下面接着写.中间这段时间也有看官方文档,发现正如他所说90%的基础内容都一样,所以这里直接跳到我比较关注的东东上,要是想看看哪些不一样,可以参考这个http://v ...
- React高阶组件学习笔记
高阶函数的基本概念: 函数可以作为参数被传递,函数可以作为函数值输出. 高阶组件基本概念: 高阶组件就说接受一个组件作为参数,并返回一个新组件的函数. 为什么需要高阶组件 多个组件都需要某个相同的功能 ...
随机推荐
- [开发笔记usbTOcan]用树莓派搭建私有Git服务器
0 | 思路 在开始编程前,先创建一个版本管理库,以前一直用SVN,但目前用Git的还是比较,正好利用这个机会学习GIt. 想过使用Github提供的免费服务器,但项目目前还没有做开源的准备,于是就有 ...
- Ajax_GET的一个基本用法
Ajax_GET的一个基本用法 首先先创建一个Server.js文件 //1.引入express// const { response } = require('express');const ex ...
- 5种高大上的yml文件读取方式,你知道吗?
原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 在上一篇文章中,我们从源码角度分析了SpringBoot解析yml配置文件的全流程,那么我们今天就来点实战,总结一下除了烂大街的@Value和@ ...
- STC8H开发(七): I2C驱动MPU6050三轴加速度+三轴角速度检测模块
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- MIME类型说明(HTTP协议中数据类型)
MIME(HTTP协议中数据类型) MIME:多功能Internet邮件扩充服务.MIME类型的格式是"大类型/小类型",并与某一种文件的扩展名相对应. 常见的MIME类型: RT ...
- 在Android中用纯Java代码布局
感谢大佬:https://www.jianshu.com/p/7aedea560f16 在Android中用纯Java代码布局 本文的完成了参考了一篇国外的教程,在此表示感谢. Android中的界面 ...
- 自定义 RestTemplate 异常处理 (转)
转自:https://ethendev.github.io/2018/11/06/RestTemplate-error-handler/ 一些 API 的报错信息通过 Response 的 body返 ...
- HTML-iframe标签
碎碎:这两天在实践中,用到了 iframe,之前对其不甚了解,了解之中遇到好多奇葩问题,今天记录下这两天遇到的相关的内容. 嵌入的 iframe 页面的边框 嵌入的 iframe 页面的背景 嵌入的 ...
- UIFont
UIFont代表字体,常见创建方法有以下几个:+ (UIFont *)systemFontOfSize:(CGFloat)fontSize; 系统默认字体+ (UIFont *)boldSystemF ...
- nodejs process uncaughtException
用过Node一段时间之后,发现那些在事件主循环里碰到的异常会导致Node进程退出.在许多应用场景下,特别是对那些希望永不当机的服务器程序来说,这都是不接受的.uncaughtException事件会提 ...