Hooks是什么?
Hooks到底是什么,React从16.8版本,推出了Hooks概念,致力于打造函数+hooks的开发体验。Vue3里也推出了组合式Api,也带来了Hooks的概念。
常见的Hook有哪些?
1.React
useState
给函数式组件中,添加状态。
import {useState} from 'react'
export default ()=> {
let [自定义名字,set自定义名字]=useState("初始值")
}
useEffect
模拟生命周期钩子函数
import {useEffect} from 'react'
export default ()=>{
//第一个参数执行函数,第二个参数不传
useEffect(() => {
//调用函数,类似于mounted
return ()=>{
//类似于destroyed
}
})
//第一个参数执行函数,第二个参数传空数组[]
useEffect(()=>{
console.log('加载完了')
},[])//这个时候就执行一次
//第一个参数执行函数,第二个参数传state数组
useEffect(()=>{
console.log('更新了','当数据变化了就会执行这个函数')
},[count,name])//第二个参数就是依赖的state
}
useContext
如果我们想要让组建的数据传递给后代组件,可以使用Context,我们需要借助createContext来帮助我们解决问题。
祖先组件
import { createContext } from "react";
import Children from "./children"
export let ZDYContext = createContext({})
const person = () => {
return (
// 使用ZDYContext.Provider 包括所有标签
<ZDYContext.Provider value={{name:'康益凡'}}>
<div>
<Children></Children>
</div>
</ZDYContext.Provider>
);
}
export default person;
子组件
import { useContext } from "react";
import { ZDYContext } from "./person";
const children = () => {
let context =useContext(ZDYContext)
return (
// 在后代组件中,我们可以通过useContext获取对应的
<div>
你好呀
<p>{context.name}</p>
</div>
);
}
export default children;
React组件的渲染机制
当一个React组件中的数据被修改时,那么这个组件就会被重新渲染,只要内部有子组件,子组件也会被重新渲染。
import { useState } from "react";
const Child = () => {
console.log('Child被渲染')
return (
<div>
<h1>Child</h1>
</div>
);
}
const Parent = () => {
console.log("Parent被渲染")
let [count, setCount] = useState(0)
return (
<div>
<h1>Parent</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
<hr />
<Child></Child>
</div>
);
}
当我们的数据count发生改变时,我们对应的Parent会被重新渲染,因为父组件重新渲染了,会导致Child也被重新渲染。
这个时候,我们就可以使用memo包裹我们的组件,下次渲染的时,直接使用对应的缓存。
import { memo } from "react";
const Child = memo(() => {
console.log('Child被渲染')
return (
<div>
<h1>Child</h1>
</div>
);
})
当我们的父组件的数据传递给子组件。这个时候对父组件的数据改变的时候子组件用来memo包裹但是子组件的数据也会更新。
memo 会对包裹的组件props进行了一个浅比较,如果props中的数据没有改变,则不会重新渲染对应的组件。
如果我们传递一个函数呢?
如果传递的是一个函数或者其它引用值,哪怕引用值本身没有发生变化,但是由于父组件的重新渲染,导致对应的引用值被重新创建,得到一个新的堆内存地址。这就导致,我们传递引用值时,哪怕添加memo,也会导致子组件重新渲染
import { useState } from "react";
const Child = () => {
console.log('Child被渲染')
return (
<div>
<h1>Child</h1>
</div>
);
}
const Parent = () => {
console.log("Parent被渲染")
let [count, setCount] = useState(0)
return (
<div>
<h1>Parent</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
<hr />
useCallback
useCallback就可以解决我们对应的问题,这个hook会把函数进行缓存。
const Parent = () => {
console.log("Parent被渲染")
let [count, setCount] = useState(0)
let [p2, setP2] = useState("可以改变,但是不去改变的p2")
let p1 = "不变的参数p1"
// let fn = () => {}
let fn = useCallback(() => {}, [])
return (
<div>
<h1>Parent</h1>
<button onClick={() => setCount(count + 1)}>+1</button>
<hr />
<Child p1={p1} p2={p2} fn={fn}></Child>
</div>
);
}
使用useCallback把函数包裹起来吗,不管我们的父组件如何被重新渲染,我们fn都还是那个函数,指向同一个推内存地址。因为memo时浅拷贝即只要堆内存地址没变就子组件也不会被重新渲染。
useCallback的第二个参数,是一个数组,当数组中的值发生变化时,useCallback就会被重新执行。让对应的fn发生改变。这个和useEffect的第二个参数一样的效果。
memo并不是必须配合useCallback使用的,useCallback也不是必须配合对应的memo使用,但是大部分情况,useCallback需要配合memo使用才能达到性能优化的效果。大部分情况,如果你直接使用过useCallback会负优化。