React Hooks 原理與最佳實踐


大家好,我是若川。持續組織了8個月源碼共讀活動,感興趣的可以?點此加我微信ruochuan12?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列。另外:目前建有江西|湖南|湖北籍前端群,可加我微信進群。


React Hooks 是 React 16.8 引入的新特性,允許我們在不使用 Class 的前提下使用 state 和其他特性。React Hooks 要解決的問題是狀態共享,是繼 render-props 和 higher-order components 之后的第三種狀態邏輯復用方案,不會產生 JSX 嵌套地獄問題。

1. 前言

React Hooks 是 React 16.8 引入的新特性,允許我們在不使用 Class 的前提下使用 state 和其他特性。React Hooks 要解決的問題是狀態共享,是繼 render-props 和 higher-order components 之后的第三種狀態邏輯復用方案,不會產生 JSX 嵌套地獄問題。

2. 狀態邏輯復用

一般來說,組件是 UI 和邏輯,但是邏輯這一層面卻很難復用。對用戶而言,組件就像一個黑盒,我們應該拿來即用。但當組件的樣式或者結構不滿足需求的時候,我們只能去重新實現這個組件。

81d808d2f405a3d9f8f2a2d39d621f8e.png

在我們開發 React 應用的時候,經常會遇到類似下面這種場景,你可能會有兩個疑問:

  1. Loading 是否可以復用?

  2. Loading 該怎么復用?

    a39c99cbd011119371ed5d5df422a91d.png

這幾個例子都指向了同一個問題,那就是如何實現組件的邏輯復用?

2.1 render props

將函數作為 props 傳給父組件,父組件中的狀態共享,通過參數傳給函數,實現渲染,這就是 render props。使用 render prop 的庫有 React Router、Downshift 以及 Formik。以下面這個 Toggle 組件為例子,我們一般可以這樣用:

4d975aa868c84d154dbbdcf63feae29b.png

可以看到,控制 Modal 組件是否展示的狀態被提取到了 Toggle 組件中,這個 Toggle 組件還可以拿來多次復用到其他組件里面。那么這個 Toggle 是怎么實現的呢?看到實現后你就會理解 render props 的原理

36800e34757eabeb899be36e8f00a97a.png

關于 render props 的更多內容可以參考 React 中文網的相關章節:Render Props

2.2 higher-order components

higher-order components 一般簡稱 hoc,中文翻譯為高階組件。從名字上就可以看出來,高階組件肯定和高階函數有什么千絲萬縷的關系。高階組件的本質是一個高階函數,它接收一個組件,返回一個新的組件。在這個新的組件中的狀態共享,通過 props 傳給原來的組件。以剛剛那個 Toggle 組件為例子,高階組件同樣可以被多次復用,常常可以配合裝飾器一起使用。

2539cec7fdf746c39e4c2b99856ca159.png

高階組件的實現和 render props 也不太一樣,主要是一個高階函數。

1e0dc64219b6959e0d61764587366d5a.png

2.3 render props 和高階組件的弊端

不管是 render props 還是高階組件,他們要做的都是實現狀態邏輯的復用,可這倆是完美的解決方案嗎?考慮一下,如果我們依賴了多個需要復用的狀態邏輯的時候,該怎么寫呢?以 render props 為例:

8d3ab5ee75b40d0ca2b021e4f2f51e47.png

看看這個代碼,你有沒有一種似曾相識的感覺?這一天,我們終于想起被“回調地獄”支配的恐懼。不得不再次祭出這張圖了。

3e17b330c2a28f7e9bc14dccbcd2bca6.png

同樣地,高階組件也會有這個問題,但由于裝飾器的簡潔性,沒有 render props 看起來那么可怕。除此之外,他們倆還有另一個問題,那就是組件嵌套過深之后,會給調試帶來很大的麻煩。這個是 render props 中組件嵌套在 React 開發者工具中的表現。

acc832e73bc783be8206ff3d98c04b8b.png

對于高階組件來說,如果你沒有對組件手動設置 name/displayName,就會遇到更嚴重的問題,那就是一個個匿名組件嵌套。畢竟上面 render props 的嵌套至少能知道組件名。

464ff73c981d41f6d36b72471f4b4c5c.png

社區里面也已經有很多解決 render props 嵌套的方案,其中 Epitath 提供了一種以 generator 的方法來解決嵌套問題,利用 generator 實現了偽同步代碼。

4c9b7c009c73b6cd818d12c5294acb08.png

更多細節可以參考黃子毅的這篇文章:精讀《Epitath 源碼 - renderProps 新用法》

2.4 React Hooks

React Hooks 則可以完美解決上面的嵌套問題,它擁有下面這幾個特性。

  1. 多個狀態不會產生嵌套,寫法還是平鋪的

  2. 允許函數組件使用 state 和部分生命周期

  3. 更容易將組件的 UI 與狀態分離

fdb15e2dd10194cb126b89504cb16900.png

上面是一個結合了 useState 和 useEffect 兩個 hook 方法的例子,主要是在 resize 事件觸發時獲取到當前的 window.innerWidth。這個 useWindowWidth 方法可以拿來在多個地方使用。常用的 Hook 方法如下:

764bee1fcebf0155e7a312f873154086.png

3. useState & useRef

useState 是 React Hooks 中很基本的一個 API,它的用法主要有這幾種:

  1. useState 接收一個初始值,返回一個數組,數組里面分別是當前值和修改這個值的方法(類似 state 和 setState)。

  2. useState 接收一個函數,返回一個數組。

  3. setCount 可以接收新值,也可以接收一個返回新值的函數。

const [ count1, setCount1 ] = useState(0);
const [ count2, setCount2 ] = useState(() => 0);
setCount1(1); // 修改 state

3.1 和 class state 的區別

雖然函數組件也有了 state,但是 function state 和 class state 還是有一些差異:

  1. function state 的粒度更細,class state 過于無腦。

  2. function state 保存的是快照,class state 保存的是最新值。

  3. 引用類型的情況下,class state 不需要傳入新的引用,而 function state 必須保證是個新的引用。

3.2 快照(閉包) vs 最新值(引用)

在開始前,先拋出這么一個問題。在 1s 內頻繁點擊10次按鈕,下面代碼的執行表現是什么?

d3316be8f09fc1755d47969fddcedb46.png

如果是這段代碼呢?它又會是什么表現?

d0d74a4c886840a9e58fd4261ab1e968.png

如果你能成功答對,那么恭喜你,你已經掌握了 useState 的用法。在第一個例子中,連續點擊十次,頁面上的數字會從0增長到10。而第二個例子中,連續點擊十次,頁面上的數字只會從0增長到1。

這個是為什么呢?其實這主要是引用和閉包的區別。

class 組件里面可以通過 this.state 引用到 count,所以每次 setTimeout 的時候都能通過引用拿到上一次的最新 count,所以點擊多少次最后就加了多少。

在 function component 里面每次更新都是重新執行當前函數,也就是說 setTimeout 里面讀取到的 count 是通過閉包獲取的,而這個 count 實際上只是初始值,并不是上次執行完成后的最新值,所以最后只加了1次。

3.3 快照和引用的轉換

如果我想讓函數組件也是從0加到10,那么該怎么來解決呢?聰明的你一定會想到,如果模仿類組件里面的 this.state,我們用一個引用來保存 count 不就好了嗎?沒錯,這樣是可以解決,只是這個引用該怎么寫呢?我在 state 里面設置一個對象好不好?就像下面這樣:

const [state, setState] = useState({ count: 0 })

答案是不行,因為即使 state 是個對象,但每次更新的時候,要傳一個新的引用進去,這樣的引用依然是沒有意義。

setState({count: state.count + 1
})

3.3 useRef

想要解決這個問題,那就涉及到另一個新的 Hook 方法 —— useRef。useRef 是一個對象,它擁有一個 current 屬性,并且不管函數組件執行多少次,而 useRef 返回的對象永遠都是原來那一個。

5fe352642a230c2af4ac8f5df3817890.png

useRef 有下面這幾個特點:

  1. useRef 是一個只能用于函數組件的方法。

  2. useRef 是除字符串 ref、函數 refcreateRef 之外的第四種獲取 ref 的方法。

  3. useRef 在渲染周期內永遠不會變,因此可以用來引用某些數據。

  4. 修改 ref.current 不會引發組件重新渲染。

useRef vs createRef:

  1. 兩者都是獲取 ref 的方式,都有一個 current 屬性。

  2. useRef 只能用于函數組件,createRef 可以用在類組件中。

  3. useRef 在每次重新渲染后都保持不變,而 createRef 每次都會發生變化。

3.4 寫需求遇到的坑

2963f68b425eb2799b09f7cd6f4d239b.png

之前在寫需求的時候遇到過這樣的一個坑。bankIdref 都是從接口獲取到的,這里很自然就想到在 useCallback 里面指定依賴。

d3275e1474d88656006b9cbfaf74d313.png

但是呢,這個 handlerReappear 方法需要在第一次進入頁面的時候,向 JS Bridge 注冊的事件,這就導致了一個問題,不管后來 handlerReappear 如何變化,registerHandler 里面依賴的 callback 都是第一次的,這也是閉包導致的問題。當然,你可能會說,我在 useEffect 里面也指定了依賴不好嗎?但要注意這是個注冊事件,意味著每次我都要清除上一次的事件,需要調用到 JS Bridge,在性能上肯定不是個好辦法。

最終,我選擇使用 useRef 來保存 bankIdref,這樣就可以通過引用來獲取到最新的值。

68a154270701b94345f9e838dea9fb64.png

3.5 Vue3 Composition API

6dc800931b6494a50bbf323f3c576a79.png

在 vue3 里面提供了新的 Composition API,之前知乎有個問題是 React Hooks 是否可以改為用類似 Vue 3 Composition API 的方式實現?

然后我寫了一篇文章,利用 Object.defineProperty 簡單實現了 Composition API,可以參考:用 React Hooks 簡單實現 Vue3 Composition API

當然這個實現還有很多問題,也比較簡單,可以參考工業聚寫的完整實現:react-use-setup

4. useEffect

useEffect 是一個 Effect Hook,常用于一些副作用的操作,在一定程度上可以充當 componentDidMountcomponentDidUpdatecomponentWillUnmount 這三個生命周期。useEffect 是非常重要的一個方法,可以說是 React Hooks 的靈魂,它用法主要有這么幾種:

  1. useEffect 接收兩個參數,分別是要執行的回調函數、依賴數組。

  2. 如果依賴數組為空數組,那么回調函數會在第一次渲染結束后(componentDidMount)執行,返回的函數會在組件卸載時(componentWillUnmount)執行。

  3. 如果不傳依賴數組,那么回調函數會在每一次渲染結束后(componentDidMountcomponentDidUpdate)執行。

  4. 如果依賴數組不為空數組,那么回調函數會在依賴值每次更新渲染結束后(componentDidUpdate)執行,這個依賴值一般是 state 或者 props。

    ffb151e189245c91055c540b4e3acf13.png

useEffect 比較重要,它主要有這幾個作用:

  1. 代替部分生命周期,如 componentDidMount、componentDidUpdate、componentWillUnmount。

  2. 更加 reactive,類似 mobx 的 reaction 和 vue 的 watch。

  3. 從命令式變成聲明式,不需要再關注應該在哪一步做某些操作,只需要關注依賴數據。

  4. 通過 useEffect 和 useState 可以編寫一系列自定義的 Hook。

4.1 useEffect vs useLayoutEffect

useLayoutEffect 也是一個 Hook 方法,從名字上看和 useEffect 差不多,他倆用法也比較像。在90%的場景下我們都會用 useEffect,然而在某些場景下卻不得不用 useLayoutEffect。useEffect 和 useLayoutEffect 的區別是:

  1. useEffect 不會 block 瀏覽器渲染,而 useLayoutEffect 會。

  2. useEffect 會在瀏覽器渲染結束后執行,useLayoutEffect 則是在 DOM 更新完成后,瀏覽器繪制之前執行。

這兩句話該怎么來理解呢?我們以一個移動的方塊為例子:

69c5b7ddafd0375b9ca841209620f955.png

75e18845018d230f0a8df14199677d41.gif

在 useEffect 里面會讓這個方塊往后移動 600px 距離,可以看到這個方塊在移動過程中會閃一下。但如果換成了 useLayoutEffect 呢?會發現方塊不會再閃動,而是直接出現在了 600px 的位置。

dbc79c64c733b6fbb3a853c927449763.png

b831a07c1ccd50065febf90657d3b616.gif

原因是 useEffect 是在瀏覽器繪制之后執行的,所以方塊一開始就在最左邊,于是我們看到了方塊移動的動畫。然而 useLayoutEffect 是在繪制之前執行的,會阻塞頁面的繪制,所以頁面會在 useLayoutEffect 里面的代碼執行結束后才去繼續繪制,于是方塊就直接出現在了右邊。那么這里的代碼是怎么實現的呢?以 preact 為例,useEffect 在 options.commit 階段執行,而 useLayoutEffect 在 options.diffed 階段執行。然而在實現 useEffect 的時候使用了 requestAnimationFramerequestAnimationFrame 可以控制 useEffect 里面的函數在瀏覽器重繪結束,下次繪制之前執行。

45bec863f682aa409bcc507ab2bdfb74.png

5. useMemo

useMemo 的用法類似 useEffect,常常用于緩存一些復雜計算的結果。useMemo 接收一個函數和依賴數組,當數組中依賴項變化的時候,這個函數就會執行,返回新的值。

const sum = useMemo(() => {// 一系列計算
}, [count])

舉個例子會更加清楚 useMemo 的使用場景,我們就以下面這個 DatePicker 組件的計算為例:

7d512f800c2057f487bc067ff2a6979a.png

DatePicker 組件每次打開或者切換月份的時候,都需要大量的計算來算出當前需要展示哪些日期。然后再將計算后的結果渲染到單元格里面,這里可以使用 useMemo 來緩存,只有當傳入的日期變化時才去計算。

6. useCallback

和 useMemo 類似,只不過 useCallback 是用來緩存函數。

6.1 匿名函數導致不必要的渲染

在我們編寫 React 組件的時候,經常會用到事件處理函數,很多人都會簡單粗暴的傳一個箭頭函數。

class App extends Component {render() {return <h1 onClick={() => {}}></h1>}
}

這種箭頭函數有個問題,那就是在每一次組件重新渲染的時候都會生成一個重復的匿名箭頭函數,導致傳給組件的參數發生了變化,對性能造成一定的損耗。

在函數組件里面,同樣會有這個傳遞新的匿名函數的問題。從下面這個例子來看,每次點擊 div,就會引起 Counter 組件重新渲染。這次更新明顯和 Input 組件無關,但每次重新渲染之后,都會創建新的 onChange 方法。這樣相當于傳給 Input 的 onChange 參數變化,即使 Input 內部做過 shadowEqual 也沒有意義了,都會跟著重新渲染。原本只想更新 count 值的,可 Input 組件 卻做了不必要的渲染。

75cf25817589f84930e2e6b16d2c8c21.png

這就是體現 useCallback 價值的地方了,我們可以用 useCallback 指定依賴項。在無關更新之后,通過 useCallback 取的還是上一次緩存起來的函數。因此,useCallback 常常配合 React.memo 來一起使用,用于進行性能優化。

a14d1974fabc5b5d9f9f6a0cc28f2922.png

7. useReducer && useContext

7.1 useReducer

useReducer 和 useState 的用法很相似,甚至在 preact 中,兩者實現都是一樣的。useReducer 接收一個 reducer 函數和初始 state,返回了 state 和 dispatch 函數,常常用于管理一些復雜的狀態,適合 action 比較多的場景。

9c4021b57b3cd02879edc1824b78cc95.png

7.2 useContext

在上一節講解 React16 新特性的時候,我們講過新版 Context API 的用法。

新版 Context 常常有一個提供數據的生產者(Provider),和一個消費數據的消費者(Consumer),我們需要通過 Consumer 來以 render props 的形式獲取到數據。如果從祖先組件傳來了多個 Provider,那最終就又陷入了 render props 嵌套地獄。

d57901ef23ac0096613188cec906482d.png

useContext 允許我們以扁平化的形式獲取到 Context 數據。即使有多個祖先組件使用多個 Context.Provider 傳值,我們也可以扁平化獲取到每一個 Context 數據。

fcf002b70b958c3435a837ddbc6ebcbf.png

7.3 實現一個簡單的 Redux

通過 useReducer 和 useContext,我們完全可以實現一個小型的 Redux。

reducer.js

159ceeaa8df2b72f3dcd404d2836febc.png

Context.js

export const Context = createContext(null);

App.js

c6fba817c0a4f39bea1826ce0b11e08e.png

8. Custom Hooks

對于 react 來說,在函數組件中使用 state 固然有一些價值,但最有價值的還是可以編寫通用 custom hooks 的能力。想像一下,一個單純不依賴 UI 的業務邏輯 hook,我們開箱即用。不僅可以在不同的項目中復用,甚至還可以跨平臺使用,react、react native、react vr 等等。編寫自定義 hook 也需要以 use 開頭,這樣保證可以配合 eslint 插件使用。在 custom hooks 中也可以調用其他 hook,當前的 hook 也可以被其他 hook 或者組件調用。以官網上這個獲取好友狀態的自定義 Hook 為例:

f30b371fe8112680014b128357326a35.png

這個自定義 Hook 里面對好友的狀態進行了監聽,每次狀態更新的時候都會去更新 isOnline,當組件卸載的時候會清除掉這個監聽。這就是 React Hooks 最有用的地方,它允許我們編寫自定義 Hook,然后這個自定義 Hook 可以復用給多個組件,并且不會和 UI 耦合到一起。

9. React Hooks 原理

由于 preact hooks 的代碼和原有的邏輯耦合度很小,這里為了更加淺顯易懂,我選用了 preact hooks 的源碼來解讀。

9.1 Hooks 執行流程

在 React 中,組件返回的 JSX 元素也會被轉換為虛擬 DOM,就是下方的 vnode,每個 vnode 上面掛載了一個 _component 屬性,這個屬性指向了組件實例。而在組件實例上面又掛載了一個 _hooks 屬性,這個 _hooks 屬性里面保存了我們執行一個組件的時候,里面所有 Hook 方法相關的信息。

ee1212f645cf60a001daf8662767729b.png

首先,我們有一個全局的 currentIndex 變量,當組件第一次渲染或者更新的時候,它會在每次進入一個函數組件的時候都重置為0,每次遇到一個 Hook 方法就會增加1,同時將這個 Hook 方法的信息放到 _list 里面。

當我們下次進來或者進入下一個組件的時候, currentIndex 又會被置為0。

組件渲染 => currentIndex 重置 0 => 遇到 Hooks 方法,放進 _list => currentIndex++ => 渲染結束

組件更新 => currentIndex 重置 0 => 遇到 Hooks 方法,獲取 _list[currentIndex]=> currentIndex++ => 重復上面步驟 => 更新結束

這個時候就會從剛才的 _list 里面根據 currentIndex 來取出對應項,所以我們每次進來執行 useState,它依然能拿到上一次更新后的值,因為這里是緩存了起來。

87d8ddeec09b0e2a3e4c34caa9434b0d.png

通過上面的分析,你就不難發現,為什么 hooks 方法不能放在條件語句里面了。因為每次進入這個函數的時候,都是要和 currentIndex 一一匹配的,如果更新前后少了一個 Hook 方法,那么就完全對不上了,導致出現大問題。

9.2 useState 和 useReducer

這樣你再來看下面 useState 和 useReducer 的源碼就會更容易理解一些。

352165c1292f8581beea510824c86cc7.png

很明顯,getHookState 是根據 currentIndex 來從 _list 里面取和當前 Hook 相關的一些信息。如果是初始化狀態(即沒有 hookState._component)這個屬性的時候,就會去初始化 useState 的兩個返回值,否則就會直接返回上一次緩存的結果。

9.3 useEffect

useEffect 和 useState 差不多,區別就在 useEffect 接收的函數會放到一個 _pendingEffects 里面,而非 _list 里面。

1e8c3c410a4876992834bc356a75a21e.png

在 diff 結束之后會從 _pendingEffects 里面取出來函數一個個執行。afterPaint 里面使用了 requestAnimateFrame 這個方法,所以傳給 useEffect 里面的方法是在瀏覽器繪制結束之后才會執行的。

98aa935d6c16103e6c388ffd09b0e4ab.png

9.4 總結

最后,這里對 React Hooks 的整個運行流程來進行一下總結和梳理。

  1. 每個組件實例上掛載一個 _hooks 屬性,保證了組件之間不會影響。

  2. 每當遇到一個 hooks 方法,就將其 push 到 currentComponent._hooks._list 中,且 currentIndex 加一。

  3. 每次渲染進入一個組件的時候,都會從將 currentIndex 重置為 0 。遇到 hooks 方法時,currentIndex 重復第二步。這樣可以把 currentIndex 和 currentComponent._hooks._list 中的對應項匹配起來,直接取上次緩存的值。

  4. 函數組件每次重新執行后,useState 中還能保持上一次的值,就是來自于步驟3中的緩存。

  5. 由于依賴了 currentComponent 實例,所以 hooks 不能用于普通函數中。

10. React Hooks 實踐

得益于 react hooks 將業務邏輯從 ui 中抽離出來,目前社區里面關于 react hooks 的實踐,大都是從功能點出發。

從最簡單的 api 封裝,例如 useDebounce、useThrottle、useImmerState 等等,再到業務層面功能封裝,比較出名的庫有 react-use、umijs/hooks 等等。

舉個栗子:umijs/hooks 的表格:

d22c96341b5a2d3c3801ae1420eb3a25.png

在后臺管理系統開發中,表格是非常常見的場景,將分頁、查詢、loading、排序等等功能打包封裝成通用 Hook,就能發揮很大的潛力。

2d30f41c330fc581b65752379f4e71c3.png

11. 推薦閱讀

  1. Umi Hooks - 助力擁抱 React Hooks

  2. 為什么 React 現在要推行函數式組件,用 class 不好嗎?

  3. useRequest- 螞蟻中臺標準請求 Hooks


a7607fc62d9332020fd1efe9c1dce657.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助4000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

63715a666078fae66db70a6ed7eda6c6.png

掃碼加我微信 ruochuan02、拉你進源碼共讀

今日話題

目前建有江西|湖南|湖北?籍 前端群,想進群的可以加我微信 ruochuan12?進群。分享、收藏、點贊、在看我的文章就是對我最大的支持~

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

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

相關文章

BW:BW增量更新方法(假增量)

1 說說假增量 我們都知道&#xff0c;對于BW來說&#xff0c;很多ECC的標準數據源自帶了增量更新功能&#xff0c;每天各種憑證產生的增量數據會自動堆積到增量隊列里&#xff0c;然后BW端做一個增量信息包按天把這些增量抽取到數據倉庫里&#xff0c;非常輕松自然&#xff0c;…

插圖 引用 同一行兩個插圖_為什么插圖是產品的重要組成部分

插圖 引用 同一行兩個插圖“Hi, my name is Ludmila and I’m a UX/UI designer”“嗨&#xff0c;我叫Ludmila&#xff0c;我是UX / UI設計師” “Hi, Ludmila”“嗨&#xff0c;路德米拉” “Welcome”“歡迎” Not anonymously at all, I’ve been doing UX/UI design fo…

如果是你你會如何重新設計和定義維基百科(wikipedia)?

日期&#xff1a;2012-8-11 來源&#xff1a;GBin1.com 最近一家設計公司發布了一個關于如何重新定義和設計維基百科的網站&#xff0c;在這里網站里詳細的刨析了如何重新設計維基百科的話&#xff0c;如何做品牌設計和網站設計&#xff0c;整個設計過程都使用非常詳細的文檔說…

祖父元素_幫助祖父母建立Skype帳戶的UX經驗教訓

祖父元素“Empathy is a key part of a UX designers arsenal”, they say. It’s drilled into our heads that we need to be thinking about our user, about their journey, about what works best for them. And it does feel empowering to boast of empathy, inside vis…

ECSHOP批量添加商品到購物車

Ecshop是一款開源的網上商店系統&#xff0c;在我心目中可以算得上網上商城界的Wordpress了。 本文介紹如何實現在ecshop中批量添加商品到購物車。 大家都知道&#xff0c;默認的ecshop只能單件點擊“添加到購物車”&#xff08;Add to Cart&#xff09;實現一件一件的添加商品…

2022年CSS的發展如何?

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以 點此加我微信ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

分布式實物實現方式_這是您完成實物產品設計任務的方式

分布式實物實現方式You’ve come to the last stages of an interview. There’s only one thing left to do: the dreaded take home design assignment.您已經到達面試的最后階段。 只剩下一件事要做&#xff1a; 可怕的帶回家的設計任務。 This is the hard part of any in…

TP-Link路由器下的多種接入模式

無線AP&#xff1a;把LAN轉成WLAN 客戶端&#xff1a;把WLAN轉成LAN 中繼&#xff1a;簡單放大上一個無線路由器的WLAN信號&#xff0c;SSID與上一個無線路由器一樣 橋接&#xff1a;與上一個無線路由器的WLAN信號連接&#xff0c;SSID與上一個無線路由器不同&#xff0c;又叫W…

type 和 interface 傻傻分不清楚?

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以 點此加我微信ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

上帝公式_感謝上帝的空白

上帝公式Do you ever walk into a room cluttered with discarded papers and leftover takeout and feel comfortable?您是否曾經走進過亂七八糟的房間&#xff1f; Yes, you might if you’re a sophomore at college. That’s just dorm life. Back in the late 90’s to …

POJ 1325 Machine Schedule(二分圖最小點集覆蓋)

題目鏈接&#xff1a;http://poj.org/problem?id1325 題意&#xff1a;A機器有n個模式&#xff0c;B機器有m個模式&#xff0c;有k個任務&#xff0c;第i個任務可以用A機器的ai模式或者B機器的bi模式&#xff0c;換模式需要重啟&#xff0c;開始兩個機器都在模式0&#xff0c;…

figma下載_在Figma上進行原型制作的各種觸發選項

figma下載Prototypes are model versions of digital products. They’re used to measure usability by testing with potential users of a product. When making prototypes with Figma, it is necessary that the actions that trigger reactions aren’t strangers and th…

通過動畫讓你深入理解 ES modules

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以 點此加我微信ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

海量數據處理之倒排索引

前言&#xff1a;本文是對博文http://blog.csdn.net/v_july_v/article/details/7085669的總結和引用 一&#xff0c;什么是倒排索引 問題描述&#xff1a;文檔檢索系統&#xff0c;查詢那些文件包含了某單詞&#xff0c;比如常見的學術論文的關鍵字搜索。 基本原理及要點&#…

ux和ui_如何為您的UX / UI設計選擇正確的原型制作工具

ux和uiAll UX/UI designers might encounter the situation of creating prototypes for wireframes or visual designs. In some cases, you may also receive the need to craft motion designs, for instance, animating icons or illustrations.所有UX / UI設計人員都可能遇…

Vue 性能指標逐漸開始反超 React 了!

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以 點此加我微信ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

制作Ubuntu U 盤啟動盤在ubuntu12.04中

制作U盤啟動盤&#xff0c;這樣就可以通過U盤來裝系統了&#xff0c;簡單便攜。 在Ubuntu下&#xff0c;從dash home中找到Startup disk creator&#xff0c;當然之前把U盤插好&#xff0c;然后很簡單的兩個選擇就好了。 轉載于:https://www.cnblogs.com/allenzhaox/archive/20…

figma下載_我如何使用Figma,CSS Grid和CSS Flexbox構建登錄頁面

figma下載I enjoy looking at website designs that are on platforms like Behance, Dribble, etc. as they are visually very pleasing to the eye. While scrolling through these designs, I always wonder about one thing, that is, how difficult would it be to expre…

2022年Web平臺的新動態

大家好&#xff0c;我是若川。持續組織了8個月源碼共讀活動&#xff0c;感興趣的可以 點此加我微信ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外…

【原創】ABAP動態編程之功能實現

根據名字獲取結構 DATA: STRUCTTYPE TYPE REF TO CL_ABAP_STRUCTDESCR. STRUCTTYPE ? CL_ABAP_TYPEDESCR>DESCRIBE_BY_NAME( SPFLI ). 根據變量獲取結構 DATA: DATATYPE TYPE REF TO CL_ABAP_ELEMDESCR,W_CHAR TYPE CHAR5. DATATYPE ? CL_ABAP_TYPEDESCR>DESCRIBE_BY_D…