[譯] React Hooks: 沒有魔法,只是數組

[譯] React Hooks: 沒有魔法,只是數組 原文鏈接: medium.com/@ryardley/r…

我是 React 新特性 Hooks 的粉絲。但是,在你使用 React Hooks的過程中,有一些看上去 很奇怪的限制 。在本文里,對于那些還在為了理解這些限制而苦苦掙扎的同志,我嘗試通過一些列圖表的方式,來解釋為什么會存在這些限制。

理解hooks怎么運行

我聽說很多同學都對hooks像魔法一般的效果感到困惑,因此我將嘗試通過淺顯的方式,來演示hooks是怎么運行的。

hooks的原則

react團隊在怎么使用hooks的 官方文檔 中,強調了兩點主要的使用原則:

  • 不要 在 循環、條件語句或者嵌套函數中調用hooks

  • 只能在 React 函數組件中調用hooks

第二點我認為是顯而易見的。為了給 函數組件 增加一些能力(比如 state,類聲明周期方法),你當然需要通過一種方式,來把這種能力賦給函數組件,這種方式就是使用hooks。

然而,第一點規則,很容易讓人感到困惑。不就是使用一個 API 么,為什么還有這么多限制呢。這也正是我將要在下文里解釋的。

hooks中的state管理,只是在操作數組

為了更加清晰的理解hooks,讓我們來看看怎么簡單實現hooks API。

請注意,下面代碼只是一個demo,是為了讓我們理解hooks大概是怎么運作的。這不是 React 中的真正內部實現。

怎么實現 useState 呢?

讓我們通過一個例子來演示,useState內部大概是怎么運作的。

組件代碼如下:

function RenderFunctionComponent() {const [firstName, setFirstName] = useState("Rudi");const [lastName, setLastName] = useState("Yardley");
?return (<Button onClick={() => setFirstName("Fred")}>Fred</Button>);
}
復制代碼

useState 實現的功能是,你能通過這個hook返回的 數組 中第二個元素,作為修改這個state的一個setter方法。

那么,React可能會怎么來實現 useState 呢?

讓我們來想想react內部會怎么來實現 useState 呢。在下面的實現里,state 是存放在被render的組件外面,并且這個state不會和其他組件共享,同時,在這個組件后續render中,能夠通過特定的作用域方式,訪問到這個state。

1) state初始化

創建兩個空數組,分別用來存放 setters 和 state,將 指針 指到 0 的位置:

2) 組件首次render

當首次render這個函數組件的時候。

每一個 useState 調用,當 首次 執行的時候,在 setter 數組里加入一個 setter 函數(和對應的數組index關聯);然后,將 state 加入對應的 state 數組里:

3) 組件后續(非首次)render

后續組件的每次render,指針都會重置為 0 ,每調用一次 useState,都會返回指針對應的兩個數組里的 state 和 setter,然后將指針位置 +1。

4)setter調用處理

每一個 setter 函數,都關聯了對應的指針位置。當調用某個 setter 函數式,就可以通過這個函數所關聯的指針,找到對應的 state,修改state數組里對應位置的值:

最后來看看useState簡單的實現

let state = [];
let setters = [];
let firstRun = true;
let cursor = 0;
?
function createSetter(cursor) {return function setterWithCursor(newVal) {state[cursor] = newVal;};
}
?
// This is the pseudocode for the useState helper
export function useState(initVal) {if (firstRun) {state.push(initVal);setters.push(createSetter(cursor));firstRun = false;}
?const setter = setters[cursor];const value = state[cursor];
?cursor++;return [value, setter];
}
?
// Our component code that uses hooks
function RenderFunctionComponent() {const [firstName, setFirstName] = useState("Rudi"); // cursor: 0const [lastName, setLastName] = useState("Yardley"); // cursor: 1
?return (<div><Button onClick={() => setFirstName("Richard")}>Richard</Button><Button onClick={() => setFirstName("Fred")}>Fred</Button></div>);
}
?
// This is sort of simulating Reacts rendering cycle
function MyComponent() {cursor = 0; // resetting the cursorreturn <RenderFunctionComponent />; // render
}
?
console.log(state); // Pre-render: []
MyComponent();
console.log(state); // First-render: ['Rudi', 'Yardley']
MyComponent();
console.log(state); // Subsequent-render: ['Rudi', 'Yardley']
?
// click the 'Fred' button
?
console.log(state); // After-click: ['Fred', 'Yardley']
復制代碼

為什么hooks的調用順序不能變呢?

如果我們根據某些外部變量,或者組件自身的state,改變hooks的調用順序,會有什么后果呢?

我們來演示下 錯誤的 做法:

let firstRender = true;
?
function RenderFunctionComponent() {let initName;if(firstRender){[initName] = useState("Rudi");firstRender = false;}const [firstName, setFirstName] = useState(initName);const [lastName, setLastName] = useState("Yardley");
?return (<Button onClick={() => setFirstName("Fred")}>Fred</Button>);
}
復制代碼

上面代碼里,我們第一個 useState 是在一個 條件分支里。我們來看看這樣引入的bug。

1) 第一次render

第一個render之后,我們的兩個state,firstName 和 lastName 都對應了正確的值。接下來看看組件第二次render的時候,會發生什么情況。

2) 第二次render

第二次render之后,我們的兩個state, firstName和 lastName 都成了 Rudi。這顯然是錯誤的,必須要避免這樣使用hooks!但是這也給我們演示了,hooks的調用順序,為什么不能改變。

react團隊明確強調了hooks的2個使用原則,如果不按照這些原則來使用hooks,將會導致我們數據的不一致性!

將hooks的操作想象成數組的操作,你可能不太會違背這些原則

OK,現在你應該清楚,為什么我們不能在條件塊或者循環語句里調用hooks了。因為調用hooks的過程中,我們是在操作數組上的指針,如果你在多次render中,改變了hooks的調用順序,將導致數組上的指針和組件里的 useState 不匹配,從而返回錯誤的 state 以及 setter 。

結論

希望我基本講明白了,hooks調用順序的大概原理。hooks是對react生態的一個很好的優化。人們對hooks感到興奮,是有原因的。如果你將hooks的操作,當做數組一樣來看待,那么你一般不會違背hooks的使用原則。

轉載于:https://juejin.im/post/5ce8071ff265da1bd30534c9

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275073.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275073.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275073.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

管理溝通中移情的應用_移情在設計中的重要性

管理溝通中移情的應用One of the most important aspects of any great design is the empathetic understanding of and connection to the user. If a design is ‘selfish’, as in when a product designed with the designer in mind and not the user, it will ultimatel…

網易前端進階特訓營,邀你免費入營!一舉解決面試晉升難題!

網易等大廠的前端崗位一直緊缺&#xff0c;特別是資深級。最近一位小哥面進網易&#xff0c;定級P4&#xff08;資深&#xff09;&#xff0c;總包60W&#xff0c;給大家帶來真實面經要點分享。網易的要求有&#xff1a;1.對性能優化有較好理解&#xff0c;熟悉常用調試工具2.熟…

Feign的構建過程及自定義擴展功能

spring-cloud-openfeign-core-2.1.1.RELEASE.jar 中 HystrixFeign 的詳細構建過程&#xff1a; EnableFeignClients -> FeignClientsRegistrar 掃描 Feign注解的類 -> FeignClientFactoryBean通過Targeter生產FeignClient -> Targeter通過Feign.Builder構建Feign ->…

angelica類似_親愛的當歸(Angelica)是第一個讓我哭泣的VR體驗

angelica類似It was a night just like any other night. I finished work for the day and closed my laptop. I had dinner and after an hour, I put on my Oculus Quest headset in order to begin my VR workout.就像其他任何夜晚一樣&#xff0c; 這 是一個夜晚。 我完成…

面試官:請手寫一個帶取消功能的延遲函數,axios 取消功能的原理是什么

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。本文倉庫 https://githu…

關于base64編碼的原理及實現

我們的圖片大部分都是可以轉換成base64編碼的data&#xff1a;image。 這個在將canvas保存為img的時候尤其有用。雖然除ie外&#xff0c;大部分現代瀏覽器都已經支持原生的基于base64的encode和decode&#xff0c;例如btoa和atob。&#xff08;將canvas畫布保存成img并強制改變…

Django web開發系列(五)模板

一 前言在上一節了解到視圖函數處理后&#xff0c;會將結果渲染到創建的html頁面&#xff0c;但html如何接收并顯示視圖函數返回的動態數據呢&#xff1f;最常用的做法就是使用模板(Template)&#xff0c;本節將簡單介紹一下模板的作用和用法。 可以這樣簡單的理解模板的概念&a…

facebook 面試_如何為您的Facebook產品設計面試做準備

facebook 面試重點 (Top highlight)Last month, I joined Facebook to work on Instagram DMs and as a way to pay it forward, I 上個月&#xff0c;我加入了Facebook&#xff0c;從事Instagram DM的工作&#xff0c;作為一種支付方式&#xff0c;我 offered to help anyone…

8年了,開始寫點東西了

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。今天分享一位大佬的文章…

荒徑 弗羅斯特_弗羅斯特龐克,顛覆性城市建設者

荒徑 弗羅斯特Most gamers are familiar with Will Wright’s famous SimCity series. It created the city building genre and there have been many attempts over the years to ape it. But few developers have been bold enough to completely deconstruct the formula; …

2012年1月份第2周51Aspx源碼發布詳情

WP7手指畫圖應用源碼 2012-01-14 [VS2010] 游戲介紹&#xff1a;Windows Phone 7手指畫圖應用 – FingerPaint&#xff0c;您通過此游戲可以隨心畫一些感興趣的東西&#xff0c;陶冶情操。操作簡單&#xff0c;頁面簡潔。適合新手學習參考。 WP7 Car Bloke(交通工具開銷記錄)源…

Gitee 如何自動部署博客 Pages?推薦用這個GitHub Actions!

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。前段時間我把自己的博客…

Java io流學習總結(三)

轉載于&#xff1a;https://www.cnblogs.com/ll409546297/p/7197911.html java.io幾種讀寫文件的方式 一、Java把這些不同來源和目標的數據都統一抽象為數據流。 Java語言的輸入輸出功能是十分強大而靈活的。 在Java類庫中&#xff0c;IO部分的內容是很龐大的&#xff0c;因為它…

現在流行的畫原型圖工具_原型資源圖:8種流行原型工具的綜合指南

現在流行的畫原型圖工具Although tools are not the most important things to learn as a UX designer, inevitably you need to use it in order to achieve your more important goals, to solve user’s problems. This article covers today’s 8 popular UX prototyping …

持續5個月,200+筆記,3千多人參與,邀請你來學源碼~

注意&#xff1a;本文點擊文末閱讀原文可查看文中所有鏈接。我正在參加掘金年度人氣作者投票活動&#xff0c;大家有空可以加微信群幫忙投票&#xff0c;感謝大家&#xff01;想起今天還沒發文&#xff0c;就開放下微信群二維碼&#xff0c;大家掃碼進群讀源碼和幫忙投票吧。群…

自己動手開發調試器 01

背景: 在做XXX編譯器檢證時經常需要區分是代碼端錯誤&#xff0c;還是編譯器端錯誤&#xff0c;因此對代碼進行調試是必不可少的。但是狗日的甲方并沒有提供對應的調試器XXXDB&#xff0c;而用GDB調試XXX生成的可執行程序很不穩定&#xff0c;經常出現異常&#xff0c;干脆…

02如何抓住重點,系統高效地學習數據結構與算法?

以下內容總結自極客時間王爭大佬的《數據結構與算法之美》課程&#xff0c;本文章僅供個人學習總結。 什么是數據結構?什么是算法? 從廣義上講&#xff0c;數據結構就是指一組數據的存儲結構。算法就是操作數據的一組方法。 類比圖書館的書籍&#xff0c;我們如果想找一本書可…

第2年,倒數第3天,1.5萬票,感動!

1源碼共讀大家好&#xff0c;我是若川。眾所周知。從8月份開始&#xff0c;我組織了源碼共讀活動&#xff0c;至今已經有5個月了&#xff0c;每周一期&#xff0c;進行到了第18期。每周堅持寫源碼解讀文章&#xff0c;每天堅持答疑解惑&#xff0c;幫助了很多人學會看源碼&…

啟發式搜索給神經網絡_神經科學如何支持UX啟發式

啟發式搜索給神經網絡重點 (Top highlight)Interaction and UX designers have long known and used heuristics to guide the creation of a user-friendly interface. We know empirically that these principles work, and they make “common sense”. These heuristics th…

Django實戰(1):需求分析和設計

Depot是《Agile Web Development with Rails》中的一個購物車應用。 該書中用多次迭代的方法&#xff0c;逐步實現購物車應用&#xff0c;使很多人走上了rails開發的道路。 遺憾的是Django世界中好像沒有類似的指引&#xff0c;也許是因為pythoner 不需要具體的例子。 但是如果…