Hook 是 React 16.8 的新增特性。它可讓你在不編寫 class 的狀況下使用 state 以及其餘的 React 特性。html
更詳細的瞭解能夠看下官網。react
//組件函數每次渲染都會被調用,每次執行都產生一個獨立的閉包
import React,{useState,useEffect} from 'react';
import {render} from 'react-dom';
function Home(){
let [count1,setCount1] = useState(0);
function alertCount1(){
setTimeout(()=>{
alert(count1);
},3000);
}
return <div>
<p>count1: {count1}</p>
<button onClick={()=>setCount1(count1+1)}>count1+</button>
<button onClick={alertCount1}>alertCount1</button>
</div>
}
render(<Home />,window.root);
複製代碼
import React,{useState,useEffect} from 'react';
import {render} from 'react-dom';
function Home(){
let [count1,setCount1] = useState(0);
//若是你熟悉 React class 的生命週期函數,你能夠把 useEffect Hook 看作 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合。
useEffect(()=>{
document.title = `這事第${count1}點擊`;
})
return <div>
<p>count1: {count1}</p>
<button onClick={()=>setCount1(count1+1)}>count1+</button>
</div>
}
render(<Home />,window.root);
複製代碼
下面每次count1加1都沒從新開啓一個新的定時器因此就會越加越快, 此次須要清除反作用。useEffect能夠返回一個函數,該函數會在組件卸載或者從新re-render前執行。算法
缺點是: 連續點擊count1加時,就會屢次建立定時器和清除定時器。也不會打印11111。redux
import React,{useState,useEffect} from 'react';
import {render} from 'react-dom';
function Home(){
let [count1,setCount1] = useState(0);
//若是你熟悉 React class 的生命週期函數,你能夠把 useEffect Hook 看作 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合。
useEffect(()=>{
let timer = setInterval(()=>{
console.log(11111);
},1000);
return ()=>{
clearInterval(timer);
}
})
return <div>
<p>count1: {count1}</p>
<button onClick={()=>setCount1(count1+1)}>count1+</button>
</div>
}
render(<Home />,window.root);
複製代碼
useEffect第二個參數是依賴項。若是設置空數組則不依賴任何參數。因此re-render時候就不會執行useEffect函數。此時useEffect返回函數只會在組件卸載的時候執行。數組
import React,{useState,useEffect} from 'react';
import {render} from 'react-dom';
function Count1(){
let [count1,setCount1] = useState(0);
//若是你熟悉 React class 的生命週期函數,你能夠把 useEffect Hook 看作 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合。
useEffect(()=>{
let timer = setInterval(()=>{
console.log(11111);
},1000);
return ()=>{
clearInterval(timer);
}
},[])
return <div>
<p>count1: {count1}</p>
<button onClick={()=>setCount1(count1+1)}>count1+</button>
</div>
}
function Home(){
let [isShow,setIsShow] = useState(false);
//若是你熟悉 React class 的生命週期函數,你能夠把 useEffect Hook 看作 componentDidMount,componentDidUpdate 和 componentWillUnmount 這三個函數的組合。
let changeShow = ()=>{
setIsShow(!isShow);
}
return <div>
<button onClick={changeShow}>show</button>
{isShow&&<Count1></Count1>}
</div>
}
render(<Home />,window.root);
複製代碼
import React,{useState,useEffect,useReducer} from 'react';
import {render} from 'react-dom';
let initCount = 1;
function countRender(state,action){
switch(action.type){
case 'ADD':
return state+action.num;
case 'REDUCE':
return state-action.num;
default:
return state;
}
}
function Home(){
//這裏熟悉redux用法的會有種親切的趕腳
//useReducer 三個參數
//第一個reducer
//第二個initialState 第三個參數的時候直接做爲初始化數據,有第三個參數的時候做爲第三個參數函數的入參。
//第三個 initializer 惰性初始化函數返回初始化數據
let [count1,dispatch] = useReducer(countRender,initCount,(state)=>10+state);
return <div>
<p>count1: {count1}</p>
<button onClick={()=>dispatch({
type:"ADD",
num:3
})}>ADD</button>
<button onClick={()=>dispatch({
type:"REDUCE",
num:2
})}>REDUCE</button>
</div>
}
render(<Home />,window.root);
複製代碼
function Home(){
let myinput = useRef();
let submit = ()=>{
console.log(myinput.current.value);
}
return <div>
<input ref={myinput} type="text"/>
<button onClick={submit}>提交</button>
</div>
}
複製代碼
import React,{useState,useEffect,useRef,useImperativeHandle} from 'react';
import {render} from 'react-dom';
function Home(){
let myinput1 = useRef();
let myinput2 = useRef();
let setInputs1 = ()=>{
myinput1.current.setValue("hello world");
myinput1.current.focus();
}
let setInputs2 = ()=>{
myinput2.current.value = "hello";
}
return <div>
<button onClick={setInputs1}>設置1</button>
<WithRefMyInputs1 ref={myinput1}/>
<button onClick={setInputs2}>設置2</button>
<WithRefMyInputs2 ref={myinput2}/>
</div>
}
function MyInputs1(props,ref){
let focusInput = useRef();
let valInput = useRef();
//自組件能夠只暴露部分操做。
useImperativeHandle(ref,()=>({
focus(){
focusInput.current.focus();
},
setValue(val){
valInput.current.value = val;
}
}))
return <div>
<div>
獲取焦點: <input ref={focusInput}/>
</div>
<div>
設置初始值: <input ref={valInput}/>
</div>
</div>
}
function MyInputs2(props,ref){
//子組件功能所有暴露
return <div>
<div>
設置初始值: <input ref={ref}/>
</div>
</div>
}
let WithRefMyInputs1 = React.forwardRef(MyInputs1);
let WithRefMyInputs2 = React.forwardRef(MyInputs2);
render(<Home />,window.root);
複製代碼
import React,{useState,useEffect,useLayoutEffect} from 'react';
import {render} from 'react-dom';
function LayoutEffect() {
const [color, setColor] = useState('red');
//用法同useEffect 只是執行時機不一樣
useLayoutEffect(() => {
alert(color);
});
useEffect(() => {
console.log('color', color);
});
return (
<>
<div style={{ background: color }}>顏色</div>
<button onClick={() => setColor('red')}>紅</button>
<button onClick={() => setColor('yellow')}>黃</button>
<button onClick={() => setColor('blue')}>藍</button>
</>
);
}
render(<LayoutEffect />,window.root);
複製代碼
//實現多個不一樣時間的倒計時功能
import React,{useState,useEffect,useLayoutEffect} from 'react';
import {render} from 'react-dom';
function formate(diffs){
let h = Math.floor(diffs/3600);
let m = Math.floor((diffs%3600)/60);
let s = diffs%60;
let zero =n=> n<10?'0'+n:n;
return `${zero(h)}:${zero(m)}:${zero(s)}`;
}
function diffTime(futureDate){
let futureTime = new Date(futureDate).valueOf();
let time = new Date().valueOf();
let diffs = (futureTime-time)/1000;
return diffs;
}
function useDiffTime(futureDate){
let [time,setTime] = useState(diffTime(futureDate));
useEffect(()=>{
setInterval(()=>{
setTime(time=>time-1);
},1000)
},[])
return time;
}
function Timer1(){
let time= useDiffTime(new Date().valueOf()+4200000);;
return <div>
倒計時{formate(time)}
</div>
}
function Timer2(){
let time= useDiffTime(new Date().valueOf()+3600000);;
return <div>
倒計時{formate(time)}
</div>
}
function Home(){
return <div>
<Timer1></Timer1>
<Timer2></Timer2>
</div>
}
render(<Home />,window.root);
複製代碼
1)把內聯回調函數及依賴項數組做爲參數傳入 useCallback,它將返回該回調函數的 memoized 版本,該回調函數僅在某個依賴項改變時纔會更新。瀏覽器
2)把建立函數和依賴項數組做爲參數傳入 useMemo,它僅會在某個依賴項改變時才從新計算 memoized 值。這種優化有助於避免在每次渲染時都進行高開銷的計算性能優化
import React,{useState,useCallback,useMemo,memo} from 'react';
import {render} from 'react-dom';
function Child({onButtonClick,data}){
console.log('Child render');
return (
<button onClick={onButtonClick} >{data.number}</button>
)
}
let MemoChild = memo(Child);
function App(){
const [number,setNumber] = useState(0);
const [name,setName] = useState('zhufeng');
const addClick = useCallback(()=>setNumber(number+1),[number]);
const data = useMemo(()=>({number}),[number]);
console.log("App render");
return (
<div>
<input type="text" value={name} onChange={e=>setName(e.target.value)}/>
<MemoChild onButtonClick={addClick} data={data}/>
</div>
)
}
render(<App />,window.root);
複製代碼
參考文獻:bash