react最常用的hooks有,useState,useEffect,useMemo,useCallback
首先我們來先聊useState,設置和改變state,代替原來的state和setState
import { useState } from "react";
import './index.css'
export default () => {
const [ count, setCount ] = useState(0);
const handleClick = ()=>{
console.log(count)//0
setCount(count + 1);
}
return (
<div className='container'>
<h3> 計算結果: {count} </h3>
<button onClick={()=>handleClick()}>每次加一</button>
</div>
);
};
setState的‘異步’並不是説內部由異步代碼實現,其實本身執行的過程和代碼都是同步的,只是合成事件和鈎子函數的調用順序在更新之前,導致在合成事件和鈎子函數中沒法立馬拿到更新後的值,形成了所謂的‘異步’(有一個變量isBatchingUpdates和batchedUpdates來處理這個問題)
useEffect 代替原來的生命週期,componentDidMount,componentDidUpdate 和 componentWillUnmount 的合併版
useEffect可以多次使用,按照先後順序執行
useLayoutEffect強制useeffect的執行為同步,並且先執行useLayoutEffect內部的函數
import React, { useState, useEffect, useLayoutEffect } from 'react';
//箭頭函數的寫法,改變狀態
const UseEffect = (props) => {
//創建了一個叫hook的變量,sethook方法可以改變這個變量,初始值為‘react hook 是真的好用啊’
const [ hook, sethook ] = useState('react hook 是真的好用啊');
const [ name ] = useState('baby張');
return (
<header className="UseEffect-header">
<h3>UseEffect</h3>
<Child hook={hook} name={name} />
{/**上面的變量和下面方法也是可以直接使用的 */}
<button onClick={() => sethook('我改變了react hook 的值' + new Date().getTime())}>改變hook</button>
</header>
);
};
const Child = (props) => {
const [ newhook, setnewhook ] = useState(props.hook);
//這樣寫可以代替以前的componentDidMount,第二個參數為空數組,表示該useEffect只執行一次
useEffect(() => {
console.log('first componentDidMount');
}, []);
//第二個參數,數組裏是hook,當hook變化時,useEffect會觸發,當hook變化時,先銷燬再執行第一個函數。
useEffect(
() => {
setnewhook(props.hook + '222222222');
console.log('useEffect');
return () => {
console.log('componentWillUnmount ');
};
},
[ props.hook ]
);
//useLayoutEffect 強制useeffect的執行為同步,並且先執行useLayoutEffect內部的函數
useLayoutEffect(
() => {
console.log('useLayoutEffect');
return () => {
console.log('useLayoutEffect componentWillUnmount');
};
},
[ props.hook ]
);
return (
<div>
<p>{props.name}</p>
{newhook}
</div>
);
};
export default UseEffect;
useMemo 是做什麼的,一言以蔽之,做性能優化用的,如果説類組件的性能優化的方法是 shouldComponentUpdate 和 PureComponent,那麼給函數組件做性能優化的就是這個 useMemo。
//parant.jsx
import React, { useState } from 'react';
import Son from '../component/Son'
export default (props)=>{
const [number,setNumber]=useState(0)
const [name, setName]=useState('Yui')
return(
<div className='flex flex-col'>
<button className='pb-10' onClick={()=>{setNumber(number+1)}}>{'number is:'+number}</button>
<button onClick={()=>{setName('rena')}}>{'change name'}</button>
<Son name={name}/>
</div>
)
}
//child.jsx
import React, { Component, useMemo } from "react";
export default (props) => {
const Data= useMemo(() =>{
console.log('render')
return props.name+'wowode'
}, [props.name])
return (
<>
<div>{Data}</div>
</>
);
};
useCallback 把內聯回調函數及依賴項數組作為參數傳入 useCallback,它將返回該回調函數的 memoized 版本,該回調函數僅在某個依賴項改變時才會更新。當你把回調函數傳遞給經過優化的並使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子組件時,它將非常有用
import React, {useState, memo, useCallback} from 'react';
function Home(props) {
console.log('Home被渲染了');
return (
<div>
<p>Home</p>
<button onClick={()=>{props.handler()}}>增加</button>
</div>
)
}
function About(props) {
console.log('About被渲染了');
return (
<div>
<p>About</p>
<button onClick={()=>{props.handler()}}>減少</button>
</div>
)
}
const MemoHome = memo(Home);
const MemoAbout = memo(About);
function App() {
console.log('App被渲染了');
const [numState, setNumState] = useState(0);
const [countState, setCountState] = useState(0);
function increment() {
setNumState(numState + 1);
}
// 以下代碼的作用: 只要countState沒有發生變化, 那麼useCallback返回的永遠都是同一個函數
const decrement = useCallback(()=>{
setCountState(countState - 1);
}, [countState]);
return (
<div>
<p>numState = {numState}</p>
<p>countState = {countState}</p>
<MemoHome handler={increment}/>
<MemoAbout handler={decrement}/>
</div>
)
}
export default App;