很久很久以前,我們在類別中使用了 React,還記得嗎?
當時,我們有了生命週期方法的概念,即接受在特定時刻執行的回調的類別上的方法。三巨頭:裝載時、更新時、卸載時。
這很重要,在類別元件上,傳回的 JSX 是在 render 方法上產生的,狀態附加到元件的 this 上,並且應用程式開發人員需要一種方法來知道在某些時刻執行操作。我們對組件生命週期的時間有了概念:
當然,您有一個重要的 API,例如forceUpdate,如果您使用的外部資料無法與 React 狀態更新連接,它允許您手動觸發重新渲染。
在概念層面上,我們有一種更直接的方式來執行應用程式的流程。生命週期方法遵循 DOM 元素的類似生命週期,您可以自行執行 memo 和 forceUpdates,同步狀態是執行邏輯的預設方式。
這種直接性被認為是簡單的,與反應式模型相比,學習這些概念更容易。但後來,Hooks 出現並改變了一切。
過渡令人困惑。首先,為了讓開發變得簡單,並在某種程度上維護開發人員所擁有的 React 模型的概念願景,許多交流試圖展示 hooks 模型的相似之處。為了擁有 3 個主要的生命週期方法,他們展示了 useEffect 的解決方法。
// componentDidMount useEffect(() => { // code... // componentWillUnmount: return function cleanup() { // code... }; }, []); // componentDidUpdate useEffect(() => { // code... }, [dependencyState, dependencyProp]);
所以,大多數用 hooks 寫的新 React 程式碼都遵循這個想法,開始同步狀態是一個自然的過程。為了保持生命週期方法的相同理念,這是呼叫 setState 並觸發重新渲染過程的地方。
有什麼問題嗎?
同步狀態成為問題,useEffect 的錯誤使用成為問題,雙重重新渲染成為問題,太多重新渲染成為問題,效能成為問題。
React 的這一步有點令人困惑,至少對我來說是這樣。因為,轉向鉤子就是轉向反應式模型,即使它是一個粗粒度的模型。但傳達的訊息是,沒有什麼大的改變。沒有關於反應性概念和理論的內容,即使使用 React 多年,我也只是閱讀 Ryan Carniato 關於反應性和固體的部落格文章才開始真正理解反應性。
即使知道 useEffect 有一個誤用,我真的不明白為什麼,而且缺乏關於反應性的概念理論使得鉤子很容易犯錯。 useEffect 成為最令人討厭的 hook,被一些人稱為“useFootgun”。關鍵是,React 中存在概念上的混亂,表現為我們今天看到的 useEffect 的所有問題。
useEffect問題不是問題的原因,而是問題的結果。
所以,這就是事情。反應性的概念中沒有生命週期。
你發生了變化,你對它做出反應,產生副作用。效果是結果,不是原因。沒有狀態同步,也沒有掛載和卸載的概念。
無論是卸載前的第一個、第十個還是最後一個渲染都沒有關係,而且鉤子不關心它,順便說一句,甚至 useEffect。
試試看:
// componentDidMount useEffect(() => { // code... // componentWillUnmount: return function cleanup() { // code... }; }, []); // componentDidUpdate useEffect(() => { // code... }, [dependencyState, dependencyProp]);
您將在控制台上看到每次狀態更新時都會執行這兩個函數。首先是清理,然後是效果回調。如果您使用帶有某些狀態或屬性的 useEffect 來進行訂閱,則每次依賴項發生變更時,都會呼叫清理函數,然後呼叫新的回調,再次進行訂閱,但使用新值。
您應該將應用程式程式碼視為簡化的 React 模型:
function EffectExample() { const [count, setCount] = useState(0); useEffect(() => { console.log('effect', count); return () => { console.log('clean up', count); } }, [count]); return ( <button onClick={() => setCount((state) => state + 1)}> {count} </button> ) }
如果您有這樣的組件:
UI = fn(state)
當您點擊按鈕並將計數加 1 時,您真正擁有的概念上是這樣的:
function Example() { const [count, setCount] = useState(0); return ( <button onClick={() => setCount((state) => state + 1)}> {count} </button> ) }
每次點擊都會再次呼叫 fn,並使用新的狀態,產生新版本的 UI。狀態應該透過使用者的操作或透過非同步派生產生的非同步值來更改。
這樣你就可以保持乾淨的想法:
渲染器需要關心在螢幕上新增、更新和刪除元素。在組件級別,重要的是:
Hooks 及其響應式模型使 React 與瀏覽器解耦,使應用程式程式碼不必關心您處於螢幕渲染過程的哪個時刻。您不再強制更新,甚至不再按照自己的規則處理備忘錄,這對於應用程式開發人員來說不太直接,但在模型方面更直接。
每次重新渲染都會產生一個結構,React 負責剩下的事情。
以上是帶鉤子的 React 中不存在生命週期的詳細內容。更多資訊請關注PHP中文網其他相關文章!