在開(kāi)發(fā)過(guò)程中,我們常常會(huì)遇到這樣的場(chǎng)景。
有一個(gè)列表,但是我們需要根據(jù)列表的不同類(lèi)型查詢(xún)并顯示對(duì)應(yīng)類(lèi)型的數(shù)據(jù)。如頭圖所示。這里有一個(gè)很明確的現(xiàn)象就是,不同的類(lèi)型會(huì)對(duì)應(yīng)不同的列表,但是當(dāng)我們代入抽象思維思考一下就能輕易發(fā)現(xiàn),除了類(lèi)型不同之外,其他的所有特性都是一樣的。
一樣的接口、一樣的 UI、一樣的類(lèi)型、一樣的交互。因此我們很容易會(huì)想到,把多個(gè)類(lèi)型的列表當(dāng)成同一個(gè)列表來(lái)處理,當(dāng) type 發(fā)生變化時(shí)去重新請(qǐng)求接口就可以輕松完成這個(gè)功能。
function ListPage() { const [list, setList] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [type, setType] = useState('all') useEffect(() => { setLoading(true) api.get('xxx/xxx/xxx', type).then(res => { setList(res.data) setLoading(false) setError('') }) }, [type]) return ( <> <Tabs type={type} onChange={setType} /> <List list={list} loading={loading} error={error} renderItem={(item) => ( <div key={item} className={s.item}>{item}</div> )} /> </> )}
這樣的處理是有一定合理性的,我相信很多小伙伴也會(huì)這樣處理。因?yàn)樗浅7险Z(yǔ)義。
不過(guò) React 新官方文檔中,提出了一個(gè)更巧妙的方式來(lái)解決這個(gè)問(wèn)題。
首先,我們可以將列表邏輯單獨(dú)拆分為一個(gè)子組件。該子組件接收參數(shù) type 作為一個(gè) props
function ListPart({type}) { const [list, setList] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') useEffect(() => { api.get('xxx/xxx/xxx', type).then(res => { setList(res.data) setLoading(false) setError('') }) }, []) return ( <List list={list} loading={loading} error={error} renderItem={(item) => ( <div key={item} className={s.item}>{item}</div> )} /> )}
然后這里的重點(diǎn)來(lái)了,在 ListPage 組件中,我們?cè)趧偛欧庋b好的子組件 ListPart 上,傳入一個(gè) key 值。這樣,我們就能夠在不顯示監(jiān)聽(tīng) type 變化的情況下,做到跟剛才一樣的效果。
function ListPage() { const [type, setType] = useState('all') return ( <div> <Tabs type={type} onChange={setType} /> <ListPart type={type} key={type} /> </div> )}
在 React 的 diff 過(guò)程中,當(dāng)一個(gè)組件的 key 值發(fā)生了變化,那么該組件將會(huì)被重新創(chuàng)建。我們也正是巧妙的利用了這個(gè)內(nèi)部邏輯,將代碼改進(jìn)成現(xiàn)在這樣。
在 ListPart 的封裝中,我們還可以借助我們之前封裝自定義 hook 的思路,進(jìn)一步簡(jiǎn)化代碼。
function ListPart({type}) { const { loading, list = [], error } = useFetch(api, type) return ( <List list={list} loading={loading} error={error} renderItem={(item) => ( <div key={item} className={s.item}>{item}</div> )} /> )}
這里面由于自定義 hook useFetch 是提前封裝好的工具方法,List 是提前封裝好的列表組件,當(dāng)我們?cè)趯?xiě)頁(yè)面頁(yè)面時(shí),整個(gè)列表的開(kāi)發(fā)工作量將會(huì)非常小。
完整代碼如下:
function ListPage() { const [type, setType] = useState('all') return ( <div> <Tabs type={type} onChange={setType} /> <ListPart type={type} key={type} /> </div> )}
function ListPart({type}) { const { loading, list = [], error } = useFetch(api, type) return ( <List list={list} loading={loading} error={error} renderItem={(item) => ( <div key={item} className={s.item}>{item}</div> )} /> )}
給子組件傳入 key 值,當(dāng) key 值發(fā)生變化,子組件會(huì)被重置。這樣的思路還可以運(yùn)用到別的類(lèi)似場(chǎng)景。
例如,你請(qǐng)求了一個(gè)書(shū)籍列表,但是某一個(gè)區(qū)域只能顯示選中的書(shū)籍的部分信息與幾條用戶(hù)評(píng)價(jià),當(dāng)我們選中別的書(shū)籍時(shí),這信息與評(píng)論都需要全部更新。
這里處理起來(lái)比較麻煩的是書(shū)籍部分信息是從父級(jí)傳遞而來(lái),而評(píng)論信息卻是需要重新請(qǐng)求獲取。
不過(guò)借助這個(gè)思路,將會(huì)非常容易做到良好的解耦,我們只需要從父級(jí)通過(guò) props 把書(shū)籍信息傳遞下來(lái),然后在子組件內(nèi)部自己去處理評(píng)論信息即可。從而斷開(kāi)評(píng)論信息與書(shū)籍切換的耦合。
function BookProfile() { ... return ( <div> ... <CurrentBookPart info={infolist[i]} key={bookid} /> </div> )}
function CurrentBookPart(props) { const [comment, setComment] = useState() ...}
合理運(yùn)用這個(gè)技巧,可以讓我們的代碼更加高效、低耦合,邏輯更加順暢。也能夠大幅度提高我們的開(kāi)發(fā)效率,快快去重新查看一下你的項(xiàng)目,有沒(méi)有可以使用這種方式重構(gòu)的地方吧。
React 新的官方文檔確實(shí)寫(xiě)得非常好,提供了許多項(xiàng)目開(kāi)發(fā)最佳實(shí)踐的思路。這些思路和實(shí)用技巧,同樣也適用于 Vue,也能夠提高我們對(duì) Vue 的使用心得。
本文鏈接:http://www.www897cc.com/showinfo-26-83618-0.html從 React 新官網(wǎng)學(xué)到的一個(gè)優(yōu)秀實(shí)踐妙招
聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com