React框架以前是采用Class类编程,在类编程中使用生命周期比较方便,但是随着迭代更新,官方开始推荐使用函数式编程,但是函数式编程就没有状态这一个概念,于是乎官方就定义了一系列钩子函数来弥补在这一缺陷,那今天我们就来学习几个实用又好用的Hooks函数。
本文是基于个人的学习分享,可能不是特别全面,本文使用的是18版本的react,使用脚手架搭建的项目。
Hooks
动机:
1.解决组件的逻辑复用。
2.解决一些class类中存在的一些问题。
定义: Hook顾名思义就是钩子的意思,在函数组件中将React的class类组件中状态以及生命周期等这些特性引入到函数组件中,这就是React的Hook函数。所以在类组件中就是不能使用hook函数。
useState
之前的函数式组件,也被称之为无状态组件,只能接受父组件传过来的props做展示,函数式组件中没有state状态也没有生命周期,而 state Hook 可以让函数式组件使用状态。
useState是React中的一个Hook函数,它是一个方法,调用的时候传入一个默认值,返回的是一个数组,其中第一项是默认状态(默认值会赋予状态),数组第二项是一个用于更新设置默认值都的函数。
因为写数组下标去获取比较麻烦,所以采用了ES6中数组的结构,直接获取到一个状态值和修改状态值的函数。
让我们用一个例子来体会一下,其中的妙用,首先需要从react中引入useState
import { useState } from 'react';
function Demo() {const [count,setCount] = useState(0);const [name,setName] = useState('寒月十九');return (<div><h3>{name}</h3><button onClick={() => { setName('十九') }}>change</button><h3>{count}</h3><button onClick={() => { setCount(count + 1) }}>add</button></div>);
}
所以useState支持多次调用,并且每一次调用返回的都是一个新的状态。
useEffect
在类组件中可以在componentDidMount
组件首次渲染结束和componentDidUpdate
组件更新中执行副作用,那在useEffect
这个钩子函数中,通过传递的参数不同,实现不同的生命周期的效果。我们直接用实际效果直观感受一下。
首先useEffect
接收两个参数,第一个参数是一个回调函数,第二个参数为依赖。
1.只传一个参数,并且里面没有返回值
import { useState } from 'react';
function Demo() {const [count,setCount] = useState(0);const [name,setName] = useState('寒月十九');useEffect(() => {console.log('副作用执行了!');})return (<div><h3>{name}</h3><button onClick={() => { setName('十九') }}>change</button><h3>{count}</h3><button onClick={() => { setCount(count + 1) }}>add</button></div>);
}
当组件渲染结束会执行一次,一加载有两次打印是因为解析jsx文件时为了解析为浏览器能读的懂得文件时,有一次组件的卸载,并再执行一次组建的渲染;当组件每次更新时都会触发这个钩子函数,相当于 ComponentDidUpdate
组件更新时。
2.只传一个参数,并且里面有返回值(返回出一个函数)
useEffect(() => { console.log('副作用执行了!'); return () => {console.log('清除副作用!'); }
})
当useEffect传递一个参数并且第一个参数返回出一个函数,这个函数可以在组件卸载时清除副作用,也就是说相当于生命周期中的 componentWillUnmount
组件卸载时。
3.传递两个参数,第一个参数为回调,第二个参数为空数组时
import { useState } from 'react';
function Demo() {const [count,setCount] = useState(0);const [name,setName] = useState('寒月十九');useEffect(() => {console.log('副作用执行了!');},[])return (<div><h3>{name}</h3><button onClick={() => { setName('十九') }}>change</button><h3>{count}</h3><button onClick={() => { setCount(count + 1) }}>add</button></div>);
}
当第二个参数依赖为空数组时,useEffect钩子函数只会在组件渲染结束执行一次,那么就相当于ComponentDidMount
组件渲染结束时。通常我们会在这个钩子函数发接口请求。
4.传递两个参数,第一个参数为回调,第二个参数为基本类型时
import { useState } from 'react';
function Demo() {const [count,setCount] = useState(0);const [name,setName] = useState('寒月十九');useEffect(() => {console.log('副作用执行了!');},[count])return (<div><h3>{name}</h3><button onClick={() => { setName('十九') }}>change</button><h3>{count}</h3><button onClick={() => { setCount(count + 1) }}>add</button></div>);
}
当第二个参数设置的基本类型发生改变时才会执行这个钩子函数,而不是当组件发生更新就执行。
我们可以记住useEffect设个钩子函数比较强大,当设置的参数不同时,可以分别代替 ComponentDidMount 、 ComponentDidUpdate 、 ComponentWillUnmount 三个生命周期的使用。
当然这个钩子函数当然不止这么几种参数配置,由于是学习笔记,并不算全面。
useRef
useRef返回一个可变的ref对象,useRef接受一个参数绑定在返回的ref对象的current属性上,返回的ref对象在整个生命周期中保持不变。
import { useRef,useEffect } from 'react';
function Demo3() {const h1Ref = useRef(null);useEffect(() => {console.log(h1Ref);},[]);return (<div><h1 ref={h1Ref}>this is h1</h1></div>)
}
useContext
这个钩子函数主要用于爷孙组件传值,useContext Hook接受一个context对象(由createContext创建的对象)作为参数,并返回Context.Consumer。
import { createContext,useContext,useState } from 'react';
const Context = createContext();// 创建一个上下文对象
function Bar() {const name = useContext(Context)return <div>Bar -- 从Demo4接收的参数:{name}</div>
}
function Foo() {return (<div>Foo<Bar /></div>)
}
function Demo4() {return (<div><Context.Provider value={'寒月十九'}><Foo /></Context.Provider></div>)
}
Bar作为Foo的子组件,Foo又是Demo中的子组件,我们使用Context组件中的Provide方法给子组件传值,必须使用value传值。
如果我传递的值是Demo4中一个有响应式的值,那子组件取到的值也会是响应式的吗?
import { createContext,useContext,useState } from 'react';
const Context = createContext();// 创建一个上下文对象
function Bar() {const name = useContext(Context)return <div>Bar --从Demo4接收的参数:{name}</div>
}
function Foo() {return (<div>Foo<Bar /></div>)
}
function Demo4() {const [name,setName] = useState('寒月十九');return (<div><Context.Provider value={name}><Foo /><button onClick={() => setName('十九')}>changeName</button></Context.Provider></div>)
}
可以看出,子组件接收到的啊参数也是响应式的。
最后
最近还整理一份JavaScript与ES的笔记,一共25个重要的知识点,对每个知识点都进行了讲解和分析。能帮你快速掌握JavaScript与ES的相关知识,提升工作效率。
有需要的小伙伴,可以点击下方卡片领取,无偿分享