自從去年年底R(shí)eact發(fā)布16.8后,React hooks已成為替換render props和HOC代碼復(fù)用方案。
本文通過(guò)一些例子來(lái)體驗(yàn)一下hooks的靈活和強(qiáng)大。
1. 如何做一個(gè)開(kāi)關(guān)組件?
老方法用renderProps實(shí)現(xiàn)代碼:
function App() {
return (
<Toggle initial={false}>
{({ on, toggle }) => (
<Button type="primary" onClick={toggle}> Open Modal </Button>
<Modal visible={on} onOk={toggle} onCancel={toggle} />
)}
</Toggle>
)
}
用hooks來(lái)實(shí)現(xiàn):
function App() {
const [open, setOpen] = useState(false);
return (
<>
<Button type="primary" onClick={() => setOpen(true)}>
Open Modal
</Button>
<Modal
visible={open}
onOk={() => setOpen(false)}
onCancel={() => setOpen(false)}
/>
</>
);
}
對(duì)比兩種實(shí)現(xiàn)方式hooks沒(méi)有了多余的嵌套組件Toggle,通過(guò)一個(gè)外部類(lèi)似全局變量的方式useState讓函數(shù)組件也能輕松擁有state。
2. 抽象分頁(yè)
相信前端開(kāi)發(fā)分頁(yè)是一個(gè)最為常用的組件,分頁(yè)需要哪些狀態(tài)呢?需要一個(gè) 當(dāng)前頁(yè)current,數(shù)據(jù)總條數(shù)total,每頁(yè)數(shù)據(jù)數(shù)量 pageSize。
如果實(shí)現(xiàn)交互?通過(guò)點(diǎn)擊上一頁(yè),下一頁(yè),或者頁(yè)碼來(lái)完成頁(yè)碼的跳轉(zhuǎn),我們需要一個(gè) click的回調(diào)函數(shù)來(lái)改變分頁(yè)的狀態(tài),實(shí)現(xiàn)頁(yè)面的數(shù)據(jù)刷新。
這樣一個(gè)業(yè)務(wù)邏輯,相信做過(guò)前端開(kāi)發(fā)的同學(xué)再熟悉不過(guò)了,通過(guò)hooks可以讓這部分分頁(yè)的邏輯代碼得到重用代碼如下:
function usePager({current=1,pageSize=10}){
const [pager, setPager] = useState({current ,pageSize });
const handleChange=({current,pageSize})=>{
setPager({current ,pageSize });
};
return {pager,handleChange};
}
// 調(diào)用方組件
function App (){
const {pager,handleChange}=usePager({});
<Pagination data={...pager} />
}
3. 實(shí)現(xiàn)復(fù)雜的狀態(tài)管理
假設(shè)一個(gè)組件和子組件狀態(tài)比較復(fù)雜,這個(gè)時(shí)候可以利用useReducer來(lái)管理狀態(tài),useReducer實(shí)際上就是一個(gè)內(nèi)置的Redux,下面是一個(gè)計(jì)數(shù)器的例子。
import React, {useReducer} from 'react';
const reducer = (state, action) => {
switch(action.type) {
case 'inc': return state + 1;
case 'dec': return state + 1;
}
return state;
};
const Counter = () => {
return (
<div>
<h1>{count}</h1>
<button onClick={() => dispatch({type: 'inc'})}>+</button>
<button onClick={() => dispatch({type: 'dec'})}>-</button>
</div>
);
};