订阅号做影视网站,我想建网站做推广,只做彩票网站犯法吗,linux wordpress 空白一、为什么需要Hook?
Hook 是 React 16.8 的新增特性#xff0c;它可以让我们在不编写class的情况下使用state以及其他的React特性#xff08;比如生命周期#xff09;。 我们先来思考一下class组件相对于函数式组件有什么优势#xff1f;比较常见的是下面的优势#xf…一、为什么需要Hook?
Hook 是 React 16.8 的新增特性它可以让我们在不编写class的情况下使用state以及其他的React特性比如生命周期。 我们先来思考一下class组件相对于函数式组件有什么优势比较常见的是下面的优势 class组件可以定义自己的state用来保存组件自己内部的状态 函数式组件不可以因为函数每次调用都会产生新的临时变量 class组件有自己的生命周期我们可以在对应的生命周期中完成自己的逻辑 比如在componentDidMount中发送网络请求并且该生命周期函数只会执行一次 函数式组件在学习hooks之前如果在函数中发送网络请求意味着每次重新渲染都会重新发送一次网络请求 class组件可以在状态改变时只会重新执行render函数以及我们希望重新调用的生命周期函数componentDidUpdate等 函数式组件在重新渲染时整个函数都会被执行似乎没有什么地方可以只让它们调用一次
所以在Hook出现之前对于上面这些情况我们通常都会编写class组件。
二、Class组件存在的问题
复杂组件变得难以理解
我们在最初编写一个class组件时往往逻辑比较简单并不会非常复杂。但是随着业务的增多我们的class组件会变得越来越复杂比如componentDidMount中可能就会包含大量的逻辑代码包括网络请求、一些事件的监听还需要在componentWillUnmount中移除而对于这样的class实际上非常难以拆分因为它们的逻辑往往混在一起强行拆分反而会造成过度设计增加代码的复杂度
难以理解的class
很多人发现学习ES6的class是学习React的一个障碍。比如在class中我们必须搞清楚this的指向到底是谁所以需要花很多的精力去学习this虽然我认为前端开发人员必须掌握this但是依然处理起来非常麻烦
组件复用状态很难
在前面为了一些状态的复用我们需要通过高阶组件或render props像我们之前学习的redux中connect或者react-router中的withRouter这些高阶组件设计的目的就是为了状态的复用或者类似于Provider、Consumer来共享一些状态但是多次使用Consumer时我们的代码就会存在很多嵌套这些代码让我们不管是编写和设计上来说都变得非常困难
三、Hook的出现
Hook的出现可以解决上面提到的这些问题 简单总结一下hooks
它可以让我们在不编写class的情况下使用state以及其他的React特性但是我们可以由此延伸出非常多的用法来让我们前面所提到的问题得到解决
Hook的使用场景
Hook的出现基本可以代替我们之前所有使用class组件的地方除了一些非常不常用的场景但是如果是一个旧的项目你并不需要直接将所有的代码重构为Hooks因为它完全向下兼容你可以渐进式的来使用它Hook只能在函数组件中使用不能在类组件或者函数组件之外的地方使用
四、Class组件和Functional组件对比
我们通过一个计数器案例来对比一下class组件和函数式组件结合hooks的对比
Class组件
import React, {PureComponent} from react;
class CounterClass extends PureComponent {constructor(props) {super(props);this.state {counter: 0}}render() {return (divh2当前计数{this.state.counter}/h2button onClick{e this.increment()}1/buttonbutton onClick{e this.decrement()}-1/button/div);}increment () {this.setState({counter: this.state.counter 1})}decrement () {this.setState({counter: this.state.counter - 1})}
}
export default CounterClass;
function组件
import React, {useState} from reactexport default function CounterHook() {/*const arr useState(0)const state arr[0]const setState arr[1]*/const [state, setState] useState(0)console.log(state, setState)return (divh2当前计数{state}/h2button onClick{e setState(state 1)}1/buttonbutton onClick{e setState(state - 1)}-1/button/div)
}
四、useState解析 Hook指的类似于useState、 useEffect这样的函数 Hooks是对这类函数的统称 那么我们来研究一下核心的一段代码代表什么意思 useState来自react需要从react中导入它是一个hook 参数初始化值如果不设置为undefined 返回值数组包含两个元素
元素一当前状态的值第一调用为初始化值元素二设置状态值的函数
点击button按钮后会完成两件事情
调用setCount设置一个新的值组件重新渲染并且根据新的值返回DOM结构
相信通过上面的一个简单案例你已经会喜欢上Hook的使用了。
Hook 就是 JavaScript 函数这个函数可以帮助你 钩入hook into React State以及生命周期等特性
但是使用它们会有两个额外的规则
只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。
五、认识useState
State Hook的API就是 useState我们在前面已经进行了学习
useState会帮助我们定义一个 state变量useState 是一种新方法它与 class 里面的 this.state 提供的功能完全相同。一般来说在函数退出后变量就会”消失”而 state 中的变量会被 React 保留。useState接受唯一一个参数在第一次组件被调用时使用来作为初始化值。如果没有传递参数那么初始化值为undefined。useState是一个数组我们可以通过数组的解构来完成赋值会非常方便。 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
FAQ为什么叫 useState 而不叫 createState?
“Create” 可能不是很准确因为 state 只在组件首次渲染的时候被创建。在下一次重新渲染时useState 返回给我们当前的 state。如果每次都创建新的变量它就不是 “state”了。这也是 Hook 的名字总是以 use 开头的一个原因。
当然我们也可以在一个组件中定义多个变量和复杂变量数组、对象
import React, {useState} from react;export default function ComplexHookState() {const [friends, setFriends] useState([bob, zep, haha])const [students, setStudents] useState([{id: 110, name: why, age: 33},{id: 111, name: zep, age: 22},{id: 112, name: haha, age: 19}])function addFriend() {friends.push(hmm)setFriends(friends)}function incrementStudentAgeWithIndex(index) {const newStudents [...students]newStudents[index].age 1setStudents(newStudents)}return (divh2好友列表/h2ul{friends.map((item, index) {return li key{index}{item}/li})}/ulbutton onClick{e setFriends([...friends, tom])}添加好友/button{/* 以下为错误做法 */}button onClick{addFriend}添加好友/buttonh2学习列表/h2ul{students.map((item, index) {return (li key{item.id}span姓名{item.name}/spanspan年龄{item.age}/spanbutton onClick{e incrementStudentAgeWithIndex(index)}age 1/button/li)})}/ul/div)
} 六、认识Effect Hook
目前我们已经通过hook在函数式组件中定义state那么类似于生命周期这些呢
Effect Hook 可以让你来完成一些类似于class中生命周期的功能事实上类似于网络请求、手动更新DOM、一些事件的监听都是React更新DOM的一些副作用Side Effects所以对于完成这些功能的Hook被称之为 Effect Hook
假如我们现在有一个需求页面的title总是显示counter的数字分别使用class组件和Hook实现 useEffect的解析
通过useEffect的Hook可以告诉React需要在渲染后执行某些操作useEffect要求我们传入一个回调函数在React执行完更新DOM操作之后就会回调这个函数默认情况下无论是第一次渲染之后还是每次更新之后都会执行这个 回调函数
七、需要清除Effect
在class组件的编写过程中某些副作用的代码我们需要在componentWillUnmount中进行清除
比如我们之前的事件总线或Redux中手动调用subscribe都需要在componentWillUnmount有对应的取消订阅
Effect Hook通过什么方式来模拟componentWillUnmount呢 useEffect传入的回调函数A本身可以有一个返回值这个返回值是另外一个回调函数B type EffectCallback () (void | (() void | undefined));
为什么要在 effect 中返回一个函数
这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数如此可以将添加和移除订阅的逻辑放在一起它们都属于 effect 的一部分
React 何时清除 effect
React 会在组件更新和卸载的时候执行清除操作正如之前学到的effect 在每次渲染的时候都会执行
八、多个useEffect一起使用
使用Hook的其中一个目的就是解决class中生命周期经常将很多的逻辑放在一起的问题
比如网络请求、事件监听、手动修改DOM这些往往都会放在componentDidMount中
使用Effect Hook我们可以将它们分离到不同的useEffect中 Hook 允许我们按照代码的用途分离它们 而不是像生命周期函数那样
React 将按照 effect 声明的顺序依次调用组件中的每一个 effect
九、Effect性能优化
默认情况下useEffect的回调函数会在每次渲染时都重新执行但是这会导致两个问题
某些代码我们只是希望执行一次即可类似于componentDidMount和componentWillUnmount中完成的事情比如网络请求、订阅和取消订阅另外多次执行也会导致一定的性能问题
我们如何决定useEffect在什么时候应该执行和什么时候不应该执行呢
useEffect实际上有两个参数参数一执行的回调函数参数二该useEffect在哪些state发生变化时才重新执行受谁的影响
案例练习 受count影响的Effect 但是如果一个函数我们不希望依赖任何的内容时也可以传入一个空的数组 [] 点击1按钮后只有修改DOM操作会受到count值变化的影响而重新render: 那么这里的两个回调函数分别对应的就是componentDidMount和componentWillUnmount生命周期函数了 componentDidMount 等价于
componentWillUnmount 等价于
import React, {useEffect, useState} from react;export default function MultiEffectHookDemo() {const [count, setCount] useState(0)const [isLogin, setIsLogin] useState(true)useEffect(() {console.log(修改DOM, count)}, [count])useEffect(() {console.log(订阅事件)return () {console.log(取消订阅事件)}}, [])useEffect(() {console.log(网络请求)}, [])return (divh2多个useEffect一起使用/h2h2{count}/h2button onClick{e setCount(count 1)} 1 /buttonh2{isLogin ? zep : 未登录}/h2button onClick{e setIsLogin(!isLogin)}登录/注销/button/div)
}