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 中直接访问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 (
<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高阶组件学习笔记
高阶函数的基本概念: 函数可以作为参数被传递,函数可以作为函数值输出. 高阶组件基本概念: 高阶组件就说接受一个组件作为参数,并返回一个新组件的函数. 为什么需要高阶组件 多个组件都需要某个相同的功能 ...
随机推荐
- Solon Web 开发,一、开始
Solon Web 开发 一.开始 二.开发知识准备 三.打包与运行 四.请求上下文 五.数据访问.事务与缓存应用 六.过滤器.处理.拦截器 七.视图模板与Mvc注解 八.校验.及定制与扩展 九.跨域 ...
- 2022年最新黑苹果monterey安装efi分享
最新版本monterey 12.1 安装. 配置: 名称 型号 备注 主板 Gigabyte Z490M Gaming X 内存 威刚万紫千红DDR4 2666 16G x 2 两条16G 插2 ...
- springMvc 启动过程
转载自https://www.jianshu.com/p/dc64d02e49ac 这里给出一个简洁的文字描述版SpringMVC启动过程: tomcat web容器启动时会去读取web.xml这样的 ...
- C++构造函数语义学(三)(基于C++对象模型)
带有虚基类的情况. 1 #include<iostream> 2 using namespace std; 3 class X 4 { 5 public: 6 int i; 7 }; 8 ...
- 数据库备份还原 mysqldump
1.备份全部数据库的数据和结构mysqldump -uroot -p123456 --all-databases >all.bakmysqldump -uroot -p123456 -A > ...
- python采用json.dump和json.load存储数据
#!/usr/bin/python # -*- coding: UTF-8 -*- import json numbers = [2,3,4,7,11,13] filename = 'numbers. ...
- BeanFactory 工厂模式
/** * BeanFactory实现类 */ public class ClassPathXmlApplicationContext implements BeanFactory { private ...
- 使用 Frp 和 Docker 通过远程桌面和 SSH 来远程控制 Windows(反向代理)
最新博客文章链接 大体思路 使用 Docker 容器,在云服务器上部署 Frps 容器来中转流量,在被控制的 Windows 上部署 Frpc 容器来暴露内网的服务,在主控制端的 Windows 上直 ...
- js window.event
转载请注明来源:https://www.cnblogs.com/hookjc/ 描述event代表事件的状态,例如触发event对象的元素.鼠标的位置及状态.按下的键等等.event对象只在事件发生的 ...
- 异步回调实现- Guava Retryer
为什么要使用重试利器Retryer 在实际开发中我们经常会遇到需要轮询查询一个接果,实现轮询的方式有很多种,我们经常要写许多代码,有时还会怕写出的代码有bug,如果已经有轮子了,我们就没必要重复造轮子 ...