时隔一年半之久再次重新学习 React,好多都还是原来的样子,这次我要重新开启 React 的大门,希望各位小伙伴可以一起讨论学习呦~
今天我们开启第四个专题:函数组件中 React Hooks 详解与实践。
在 16.8 版本之后的 React 发布了新特性 Hooks。 本篇文章主要对该新特性进行了详细讲解,并对一些常用的 Hooks 进行代码演示,希望可以对需要的小伙伴提供一些帮助。
Hooks 是 React v16.7.0-alpha 中加入的新特性。它可以让你在 class
以外使用 state
和其他 React 特性。
这个 API 是 React 的未来,各位有必要深入理解。
Hook
这个单词的意思是"钩子"。
React Hooks
的意思是:组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。 React Hooks 就是那些钩子。
当我们需要什么功能,就使用什么钩子。React 默认提供了一些常用钩子,你也可以封装自己的钩子。
所有的钩子都是为函数引入外部功能,所以 React 约定,钩子一律使用 use
前缀命名,便于识别。你要使用 xxx 功能,钩子就命名为 usexxx。
比如:useState
就是一个 Hook,可以在我们不使用 class
组件的情况下,拥有自身的 state
,并且可以通过修改 state
来控制 UI 的展示。
import React, { useState } from 'react';
function Foo() {
// 声明一个名为 “count” 的新状态变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
export default Foo;
是不是在函数式组件里使用 Hooks 很方便?那我们在对比一下实现同样的功能,在类组件中使用呢。
import React, { Component } from "react";
export default class Foo extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
这个类组件仅仅是实现了一个点击累加的功能,但可以看到,它的代码已经很"重"了。真实的 React App 由多个类按照层级,一层层构成,复杂度成倍增长。再加入 Redux,就变得更复杂。
常用的几个:
useState()
useEffect()
useReducer()
useContext()
简单了解:
useCallback()
useMemo()
useRef()
useLayoutEffect()
useImperativeHandle()
语法
const [state, setState] = useState(initialState)
// 传入唯一的参数: initialState,可以是数字,字符串等,也可以是对象或者数组。
// 返回的是包含两个元素的数组:第一个元素,state 变量,setState 修改 state 值的方法。
优化方案
在创建初始状态是比较昂贵的,所以我们可以在使用 useState
API 时,传入一个函数,就可以避免重新创建忽略的初始状态。
// createRows 只会被执行一次
const [rows, setRows] = useState(() => createRows(props.count));
之前很多具有副作用的操作,例如网络请求,修改 UI 等,一般都是在 class 组件的 componentDidMount
或者 componentDidUpdate
等生命周期中进行操作。而在函数组件中是没有这些生命周期的概念的,只能 return
想要渲染的元素。
但是现在,在函数组件中也有执行副作用操作的地方了,就是使用 useEffect
函数。
语法
useEffect(() => { doSomething });
/*
* 参数:
* 第一个是一个函数,是在第一次渲染以及之后更新渲染之后会进行的副作用。
* 这个函数可能会有返回值,倘若有返回值,返回值也必须是一个函数,会在组件被销毁时执行。
* 第二个参数是可选的,是一个数组,数组中存放的是第一个函数中使用的某些副作用属性。用来优化 useEffect
* 如果使用此优化,请确保该数组包含外部作用域中随时间变化且 effect 使用的任何值。 否则,您的代码将引用先前渲染中的旧值。
* 如果要运行 effect 并仅将其清理一次(在装载和卸载时),则可以将空数组([])作为第二个参数传递。 这告诉 React 你的 effect 不依赖于来自 props 或 state 的任何值,所以它永远不需要重新运行。
*/
注意
虽然传递
[]
更接近熟悉的componentDidMount
和componentWillUnmount
执行规则,但我们建议不要将它作为一种习惯,因为它经常会导致错误。
优化方案
useEffect
的第二个参数是一个数组,里面放入在 useEffect
使用到的 state
值,可以用作优化,只有当数组中 state
值发生变化时,才会执行这个 useEffect
。
useEffect(() => {
// 使用浏览器API更新文档标题
document.title = `You clicked ${count} times`;
}, [ count ]);
Tip:如果想模拟
class
组件的行为,只在componetDidMount
时执行副作用,在componentDidUpdate
时不执行,那么useEffect
的第二个参数传一个[]
即可。(但是不建议这么做,可能会由于疏漏出现错误)
语法
const [state, dispatch] = useReducer(reducer, initialArg, init);
useState
的替代方案。 接受类型为 (state, action) => newState 的reducer
,并返回与 dispatch
方法配对的当前状态。
当你涉及多个子值的复杂 state
(状态) 逻辑时,useReducer
通常优于 useState
。
优化:延迟初始化
还可以惰性地创建初始状态。为此,你可以将init函数作为第三个参数传递。初始状态将设置为 init(initialArg)
。
与 useState
的区别
state
状态值结构比较复杂时,使用 useReducer
更有优势。useState
获取的 setState
方法更新数据时是异步的;而使用 useReducer
获取的 dispatch
方法更新数据是同步的。语法
const value = useContext(MyContext);
注意
useContext
必须是上下文对象本身的参数:
useContext(MyContext)
useContext(MyContext) 只允许您阅读上下文并订阅其更改。您仍然需要
在树中使用以上内容来为此上下文提供值。
其他后面几个 Hooks 的用法我将在最近进行补充,感谢大家支持!
后续待补充…
希望以上内容可以帮助到大家。我也是重新开始学习 React,欢迎大家一起讨论学习,最后不要忘记一键三连哦~
如果有什么不对或不严谨的地方,欢迎大家能提出宝贵的意见,十分感谢。
各位 加油!
参考文档:
React 官网
React Hooks FAQ
✨ 原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐️ 收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️ 评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!