react中useRef和useMemo和useCallback
memo
: 被memo包裹的组件,会浅层比较 props
,不会深度比较,如果浅层比较相同,就不会重新渲染组件
默认是,无论怎么,都会重新渲染一遍子组件,,
useMemo
: 包裹一个函数,返回一个值,,只会在监听的状态改变的时候,才会重新执行一遍这个函数
这两个用来避免重新渲染,子组件,,或者重新执行一个复杂的函数,,,在不需要的情况下,,比如说,你的状态改变跟某个子组件没有关系,,就不用触发这个子组件的重新渲染
父组件:
import {useMemo, useState} from "react";
import ChildComponent from "./children/ChildComponent";
function HeheMemo(){
const [count, setCount] = useState(0)
const [text, setText] = useState("")
function expensiveResult(){
console.log("recalculate...")
// return Math.random().;
return Math.floor(Math.random()*1000000)
}
const memoizedValueValue = useMemo(()=>expensiveResult(),[count])
// 只有当count变化的时候,才会重新渲染子组件
const memoizedChild = useMemo(()=>{
return <ChildComponent count={count}/>
},[count])
return(
<div>
<h1>expensive calculation</h1>
<ChildComponent count={count} />
<div>count : {count}</div>
<div>expensive {memoizedValueValue} </div>
<button onClick={()=>setCount(count+1)}>btn</button>
<input type="text" onChange={e=>setText(e.target.value)}/>
</div>
)
}
export default HeheMemo
子组件:
import React, {memo} from "react";
// interface ChildProps extends React.ComponentProps<any>
interface ChildProps{
count:number
}
const Child = memo((props:ChildProps)=>{
console.log("我被渲染了")
return (
<div> child component --{props.count} </div>
)
})
export default Child
useRef
setState 会触发页面的重新渲染,,就会重新执行函数,,,,像那种计时器,如果第二次渲染就变了,,需要保证是同一个定时器,,使用useRef,,
useEffect()只会在依赖变化的时候重新执行,,如果依赖没有变化,他取得就是最开始的那个状态,,,闭包中的函数和变量是静态的,,函数捕获了定义时的变量环境,,后续无法感知变量的变化
import React, {Component, useEffect, useRef, useState} from 'react';
function Hello02() {
const [text, setText] = useState("")
function handleClick(){
console.log("click with text"+text)
}
const clickRef = useRef<Function>(null);
clickRef.current = handleClick
/**
* 初次渲染 ===》 clickRef被赋值,,
* 后续渲染 ===》 setText() ==> 更新状态,触发再次渲染 ==》 clickRef重新被赋值
*
*
* 闭包中的函数和变量是静态的,,函数捕获了定义时的变量环境,,后续无法感知变量的变化
*/
useEffect(()=>{
const interval = setInterval(()=>{
clickRef.current?.()
},1000)
return ()=>clearInterval(interval)
},[])
return (
<div>
<input type="text" value={text} onChange={e=>setText(e.target.value)}/>
<button onClick={handleClick}>btn</button>
</div>
)
}
export default Hello02;
useState:可以获取之前的状态
const startTimer = ()=>{
if (!timeRef.current){
timeRef.current = window.setInterval(()=>{
setCount(prevState => prevState+1)
},1000)
}
}
useCallback
父组件在传递回调函数给子组件的时候,,如果父组件更改了状态,重新渲染,,这个函数会被重新创建,返回一个新的函数,,这个新的函数的引用,,让props改变了,导致子组件,,即使使用了 memo
,,也会重新渲染
使用 useCallback
记忆化回调函数,,这个函数就不会返回新的引用
import {memo, useCallback, useState} from "react";
interface ChildProps{
onClick:()=>void
}
const Child = memo(({onClick}:ChildProps)=>{
console.log("child render...")
return (
<div onClick={onClick}>child</div>
)
})
function Parent(){
const [count, setCount] = useState(0)
// function handleClick(){
// console.log("click")
// }
const handleClick = useCallback(()=>{
console.log("click")
},[])
return (
<div>
<p>{count}</p>
<button onClick={e=>setCount(count+1)}>btn</button>
<Child onClick={handleClick}></Child>
</div>
)
}
export default Parent