群友在一次字節(jié)的面試中,被要求實(shí)現(xiàn) useToggle。
useToggle 表示兩個(gè)狀態(tài)的來回切換。
群友一想,這還不簡單,于是就咔咔一頓寫,兩三筆就把該功能實(shí)現(xiàn)了。
function useToggle(value: boolean) { const [state, setState] = useState(value) const toggle = () => { setState(!state) } return {state, toggle}}
搞完之后,面試官看到代碼卻說:
不太對,組件重新渲染,導(dǎo)致這個(gè) hook 重新執(zhí)行了,狀態(tài)就變了。
這下直接給群友整不會了,咋回事?為什么字節(jié)面試官說的東西跟他理解的不一樣。百思不得其解之下,在面試之后又去研究了很多方案,最后實(shí)在沒想通,又跑到群里來討論。
那么問題來了,截圖中,群友口中所說的字節(jié)面試官的這種說法是否靠譜呢?
從功能實(shí)現(xiàn)的角度上來說,上面那一段代碼,其實(shí)是沒有任何的問題的。
當(dāng)組件重新渲染時(shí),hook 會不會重新執(zhí)行?當(dāng)然會。
但是 hook 重新執(zhí)行,狀態(tài)會不會發(fā)生變化?不會。
這里我們討論的是由其他狀態(tài)的變化導(dǎo)致組件 re-render,從而導(dǎo)致 toggle 的狀態(tài)被重置或者變化。
在 React 中,hook 是基于閉包來實(shí)現(xiàn),因此幾乎每個(gè) hook 理論上都具有緩存能力。我們常用的這些 hook:useState、useRef useReducer useEffect useMemo useCallback 他們都有一些共性,那就是緩存能力。然后在語義上有一些差異。
面試官這樣的說法,很明顯是在學(xué)習(xí)的時(shí)候,跟許多人犯了同樣一個(gè)錯(cuò)誤,只關(guān)注了他們差異的部分,而沒有關(guān)注他們共性的部分。
因此,在群友的這段實(shí)現(xiàn)中,如果由其他狀態(tài)引發(fā)的 hook 重新執(zhí)行,useToggle 的狀態(tài)會被 useState 緩存,狀態(tài)本身的值不會發(fā)生變化。否則,React 的根基都要被動搖了。
那么面試官為什么要這樣說呢?
一種可能就是面試官本身在工作實(shí)踐中沒有正確理解 React 的 hook,并且過于依賴了 useMemo useCallback,忽視了其他 hook 的緩存能力導(dǎo)致了錯(cuò)誤的解讀。
另外一種情況就是在沒有得到自己想要的答案時(shí),自動切入了壓力測試環(huán)節(jié),試圖通過否定候選人逼問出滿意的答案。或者通過壓力測試觀察候選人的知識面中更多的維度。
有的。該群友找到了 ahook 的實(shí)現(xiàn),代碼如下:
function useTgoggle2(value: boolean, reverseValue?: boolean) { const [state, setState] = useState(value) const actions = useMemo(() => { const reverseValueOrigin = reverseValue === undefined ? !value : reverseValue; const toggle = () => { setState(prev => { return prev === value ? reverseValueOrigin : value }) } return toggle }, []) return {state, actions}}
和他寫的版本相比,代碼看上去豐滿了許多。一看就很高端。
但是另他想不通的地方在于,使用了 useMemo 之后,和他寫的那個(gè)版本,有什么區(qū)別嗎?或者說,有什么好處嗎?
他的第一個(gè)解讀是,useMemo 因?yàn)榫彺媪撕瘮?shù),所以減少了函數(shù)的重復(fù)聲明。
這種理解對不對呢?錯(cuò)。
許多人都會有這樣的誤解。事實(shí)卻是,useMemo useCallback 不會減少函數(shù)的聲明。
我們把匿名函數(shù),換成一個(gè)有名字的函數(shù),就能快速理解了。
function xxx() { const reverseValueOrigin = reverseValue === undefined ? !value : reverseValue; const toggle = () => { setState(prev => { return prev === value ? reverseValueOrigin : value }) } return toggle}const actions = useMemo(xxx, [])
實(shí)際上在 useMemo 執(zhí)行之前,函數(shù) xxx 都會重新聲明。包括 useMemo 傳入的第二個(gè)參數(shù)的空數(shù)組,它也是被重新聲明的。
useMemo 控制的是賦值次數(shù),而不是聲明次數(shù)。
既然這樣,又不能減少函數(shù)聲明次數(shù),那 useMemo 的作用在哪里呢?
在這個(gè)案例中,他的作用就是:保持 actions 的引用穩(wěn)定。當(dāng)組件重新渲染時(shí),actions 的引用不會因?yàn)?nbsp;re-render 而發(fā)生變化。
這樣,當(dāng)使用者將 actions 作為參數(shù)傳遞給其他組件時(shí),可以保證 actions 的引用是沒有發(fā)生變化的。
const {state, actions} = useToggle(true)...<OtherComponent actinotallow={actions} />
那么這個(gè)時(shí)候,如果我們在聲明 OtherComponent 時(shí)使用了 memo,OtherComponent 就不會因?yàn)楦附M件的 re-render 而重新渲染。
這里需要明確的是,單獨(dú)使用 memo 是沒有用的。關(guān)于更具體的細(xì)節(jié),在我們之前的性能優(yōu)化章節(jié)中有詳細(xì)聊到。
當(dāng)然實(shí)際上這里就涉及到另外一個(gè)問題的探討,我們是否應(yīng)該在工具庫底層使用 useCallback 或者 useMemo 來緩存函數(shù)的引用呢?
實(shí)際上在付費(fèi)群里我們曾經(jīng)對這個(gè)問題也有過爭議。
我個(gè)人的觀點(diǎn)是:沒有必要。因?yàn)閷τ谑褂谜叨裕覀兿胍WC性能優(yōu)化的目標(biāo)達(dá)成,那么就必須同時(shí)使用 useMemo/useCallback + memo。他們兩的共同作用下,能減少函數(shù)的 re-render,從而達(dá)到性能優(yōu)化的目的。
一種情況是,需要這樣做的場景很少。
另外一種情況是,這可能對使用者造成誤解。認(rèn)為只需要 memo 就可以完成性能優(yōu)化了。
這種優(yōu)化方式不是完全無感的,他需要使用者配合另外一半。因此這就要求使用者必須完全了解工具庫的底層實(shí)現(xiàn)才可以完美的配合你。或者更聰明的使用者也不會關(guān)注你底層是怎么實(shí)現(xiàn),他自己又單獨(dú)包裹一層 useMemo/useCllback。
咋說呢,這個(gè)現(xiàn)象其實(shí)非常普遍。
很多人在面試的時(shí)候,特別是在面一些好團(tuán)隊(duì)時(shí),遇到這種情況都會很懵逼。被人否定之后就習(xí)慣性地懷疑自己的答案有問題。從而導(dǎo)致后面的回答因?yàn)榫o張和自我懷疑陷入一種惡性循環(huán),給人一種整場表現(xiàn)都很差的感覺。
有幾種不同的情況會出現(xiàn)這種局面。
有的面試官比較善于抓住候選人的缺點(diǎn)不停拷打,進(jìn)而證明候選人能力不足。這其實(shí)違背了面試的本質(zhì)。好的面試官反而更應(yīng)該懂得如何挖掘候選人的優(yōu)勢,而不是在候選人不擅長的點(diǎn)上反復(fù)糾纏。
當(dāng)然,這也可以理解,現(xiàn)在越來越多的面試官會陷入這種困境,很大一部分原因是因?yàn)樘嗟那舐氄咴诤啔v、面試中夸大自己的能力,把本來不屬于自己的項(xiàng)目經(jīng)歷包裝成自己的,面試官與求職者信任關(guān)系的破裂,是主要是的因素之一。
當(dāng)然,還有一部分原因是因?yàn)樾枰诰騽e人的優(yōu)勢對面試官本身的個(gè)人能力有非常高的要求,并不是每個(gè)面試官都具備這樣的能力。因此,在這種情況下,一個(gè)比較好的技巧和方式就是主動自己先明確好自己的優(yōu)勢在哪里,并且在聊天過程中主動展示。
除此之外,也包括部分求職者,屬于是找了半天,渾身下上就沒可挖掘的優(yōu)勢。
壓力測試。或者說,故意在面試過程中給求職者施加壓力。讓求職者認(rèn)為自己在這場面試?yán)锉憩F(xiàn)得不好。哪怕有的面試官對求職者非常欣賞,也不會表現(xiàn)出來。
所以很多時(shí)候,有的人雖然自己拿到了 offer,但是自己都感覺非常意外,因?yàn)樽晕腋杏X確實(shí)面試表現(xiàn)不是很好,在這種情況下還能拿到 offer,實(shí)屬是萬萬沒想到。
當(dāng)然,為什么要這樣做,不同的團(tuán)隊(duì)有不同的原因,可能是為了看看別人在壓力環(huán)節(jié)下的表現(xiàn),可能是為了更好的打壓薪資,或者是為了讓求職者更加珍惜這個(gè)工作機(jī)會等等。
但是壓力測試也不是每個(gè)面試官都能輕松拿捏的,經(jīng)常容易玩崩,讓別人對你這里的面試體驗(yàn)感覺非常差。
確實(shí)是求職者思路不對,回答錯(cuò)了。這種情況下最好是能在面試官的引導(dǎo)下快速思考錯(cuò)誤原因,并給出正確的解法。當(dāng)然,如果實(shí)在不行,就直接承認(rèn)自己確實(shí)這方面比較薄弱比較好。但是不少人為了補(bǔ)救,會多說很多不沾邊的內(nèi)容,反而會錯(cuò)得更離譜。
許多人雖然掌握了某些知識,但是沒有構(gòu)建完整的知識體系,因此在面對別人反問或者質(zhì)問時(shí)會表現(xiàn)得非常慌亂。
完善自己的知識體系,對自己所表達(dá)的觀念和結(jié)論有篤定的判斷,可以避免在這種情況之下讓溝通往更壞的情況發(fā)展。
本文鏈接:http://www.www897cc.com/showinfo-26-91024-0.html一道字節(jié)面試題,把群友整不會了,關(guān)于 useMemo 用法的另外一個(gè)延伸
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com