<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] # 介紹 React 是主流的前端框架,v16.8 版本引入了全新的 API,叫做 [React Hooks](https://zh-hans.reactjs.org/docs/hooks-reference.html),顛覆了以前的用法。 如果你是 Hook 初學者,建議先閱讀 [https://usehooks.com/](https://usehooks.com/) 以及 [Dan Abramov 的個人博客](https://overreacted.io/)。 axios 以及 immer 等庫都未能 “幸免”,被 Hook 包裹了一層而變成了 [axios-hooks](https://github.com/simoneb/axios-hooks) 以及 [use-immer](https://github.com/immerjs/use-immer)。 # 思想 React 團隊希望,組件不要變成復雜的容器,最好只是數據流的管道。開發者根據需要,組合管道即可。**組件的最佳寫法應該是函數,而不是類。** React 的函數組件,有重大限制: 1. 必須是純函數 2. 不能包含狀態 3. 也不支持生命周期方法 4. 因此無法取代類(沒有 this) **React Hooks 的設計目的,就是加強版函數組件,組件盡量寫成純函數,如果需要外部功能和副作用,就用鉤子把外部代碼 "鉤" 進來。** React Hooks 就是那些鉤子。 # 鉤子函數 React 為我們提供的鉤子: * [Basic Hooks](https://zh-hans.reactjs.org/docs/hooks-reference.html#basic-hooks) * [`useState`](https://zh-hans.reactjs.org/docs/hooks-reference.html#usestate) * [`useEffect`](https://zh-hans.reactjs.org/docs/hooks-reference.html#useeffect) * [`useContext`](https://zh-hans.reactjs.org/docs/hooks-reference.html#usecontext) * [Additional Hooks](https://zh-hans.reactjs.org/docs/hooks-reference.html#additional-hooks) * [`useReducer`](https://zh-hans.reactjs.org/docs/hooks-reference.html#usereducer) * [`useCallback`](https://zh-hans.reactjs.org/docs/hooks-reference.html#usecallback) * [`useMemo`](https://zh-hans.reactjs.org/docs/hooks-reference.html#usememo) * [`useRef`](https://zh-hans.reactjs.org/docs/hooks-reference.html#useref) * [`useImperativeHandle`](https://zh-hans.reactjs.org/docs/hooks-reference.html#useimperativehandle) * [`useLayoutEffect`](https://zh-hans.reactjs.org/docs/hooks-reference.html#uselayouteffect) * [`useDebugValue`](https://zh-hans.reactjs.org/docs/hooks-reference.html#usedebugvalue) # `useState ()` 在初始渲染期間,返回的狀態 (`state`) 與傳入的第一個參數 (`initialState`) 值相同。 在后續的重新渲染中,`useState`返回的第一個值將始終是更新后最新的 state。 ``` function Counter({initialCount}) { // 返回一個數組 const [count, setCount] = useState(initialCount); // Declare multiple state variables! const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]); return ( <> Count: {count} <button onClick={() => setCount(initialCount)}>Reset</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> <button onClick={() => setCount(c=> c + 1)}>+</button> </> ); } ``` **第二個成員**是一個函數,用來更新狀態,約定是`set`前綴加上狀態的變量名(上例是`setButtonText`)。 > [2020要用immer來代替immutable優化你的React項目](https://blog.csdn.net/GetIdea/article/details/103770851) 小結: * React 會在重復渲染時保留 state。 * `useState`會返回一對值:**當前**狀態和一個讓你更新它的函數,你可以在事件處理函數中或其他一些地方調用這個函數。 * 更新函數 類似 class 組件的`this.setState`,但是它不會把新的 state 和舊的 state 進行合并。 * `setCount(c => c + 1)` // ? 在這不依賴于外部的 `count` 變量,每次`setCount`內部的回調取到的`count`是最新值(在回調中變量命名為`c`)。 # `useEffect ()` 默認情況下,第一次渲染之后和每次更新之后會運行 `useEffect()`。 effect 的全稱應該是 Side Effect,中文名叫副作用,我們在前端開發中常見的副作用有: * dom 操作 * 瀏覽器事件綁定和取消綁定 * 發送 HTTP 請求 * 打印日志 * 訪問系統狀態 * 執行 IO 變更操作 示例: ``` // 添加了 數組項 personId 數據源依賴項時,根據該數據源是否變化來決定是否觸發回調 useEffect(() => { setLoading(true); fetch(`https://swapi.co/api/people/${personId}/`) .then(response => response.json()) .then(data => { setPerson(data); setLoading(false); }); }, [personId]) ``` * 可以返回一個函數,來進行額外的[清理副作用](https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup)。(類似類組件的 `componentWillUnmount` 時觸發) ``` useEffect(() => { const subscription = props.source.subscribe(); return () => { // 清理訂閱 subscription.unsubscribe(); }; }); ``` * 可以將 `useEffect` Hook 看作 `componentDidMount`,`componentDidUpdate` 和`componentWillUnmount` 的組合。 整個組件的生命周期流程可以這么理解: > **組件掛載** --> 執行副作用 --> **組件更新** --> 執行清理函數 --> 執行副作用 --> ... --> **組件卸載** 小結: * React 會等待瀏覽器完成畫面渲染之后才會延遲調用`useEffect`,因此會使得額外操作很方便 * effect 的清除階段在每次重新渲染時都會執行,而不是只在卸載組件的時候執行一次 * `useEffect`會在調用一個新的 effect 之前對前一個 effect 進行清理 * React 將按照 effect 聲明的順序依次調用組件中的每一個 effect * 如果想執行**只運行一次的 effect(僅在組件掛載/卸載(mount/unmount)時執行),可以傳遞一個空數組(`[]`)作為第二個參數**。這就告訴 React 你的 effect 不依賴于 `props` 或 `state` 中的任何值,所以它永遠都不需要重復執行。這并不屬于特殊情況 —— 它依然遵循輸入數組的工作方式。 # `useContext ()` 1. 使用 React Context API,在組件外部建立一個 Context。 ``` import { createContext } from "react"; const AppContext =createContext(); ``` 組件封裝代碼如下: ``` <AppContext.Provider value={{ username: 'superawesome' }}> <div className="App"> <Navbar/> <Messages/> </div> </AppContext.Provider> ``` 上面代碼中,`AppContext.Provider`提供了一個 Context 對象,這個對象可以被子組件共享。 2. 子組件需要 `useContext()` 鉤子函數用來引入 Context 對象,從中獲取 `username`屬性。 ``` const Navbar = () => { const { username } = useContext(AppContext); return ( <div className="navbar"> <p>AwesomeSite</p> <p>{username}</p> </div> ); } ``` # `useReducer ()` Redux 的 Reducer 函數的形式是 `(state, action) => newState`。 `useReducer()` 鉤子用來引入 Reducer 功能。 (??:真不愧是 Redux 作者啊,還是用的 redux 的方式) > React 會確保`dispatch`函數的標識是穩定的,并且不會在組件重新渲染時改變。這就是為什么可以安全地從`useEffect`或`useCallback`的依賴列表中省略`dispatch`。 ``` import React, { useReducer } from "react"; ... // 定義 reducer const myReducer = (state, action) => { switch(action.type) { case('countUp'): return { ...state, count: state.count + 1 } default: return state } } function App() { // 參數為:reducer 和初始狀態,返回的數組為:更新后的狀態和 dispatch 用來分發狀態。 const [state, dispatch] = useReducer(myReducer, { count: 0 }); return ( <div className="App"> <button onClick={() => dispatch({ type: 'countUp' })}> +1 </button> <p>Count: {state.count}</p> </div> ); } ... ``` # `useRef()` [`useRef()`](https://zh-hans.reactjs.org/docs/hooks-reference.html#useref)Hook 不僅可以用于 DOM refs。「ref」 對象是具有一個可變`current`屬性且可以容納任意值的通用容器,類似于一個 class 的實例屬性 ``` // initialValue 可有可無,或者設置為 null const savedCallback = useRef(initialValue); function callback() { setCount(count + 1); } useEffect(() => { // 可以賦任意值到 current 屬性中,進行保存 savedCallback.current = callback; }); ``` `useRef()` 返回**一個帶有 `current` 可變屬性(初始值為`initialValue`)的普通對象**在每一次渲染之間共享。 請記住,`useRef` 的內容更改時不會通知您。 更改 `current` 屬性不會導致重新渲染。 # `useCallback` 與 `useMemo` 1. `useCallback` 返回一個[`memoized`](https://en.wikipedia.org/wiki/Memoization)回調函數。 2. `useMemo` 返回一個 任何值,參數:一個具有返回?value?的函數、依賴項數組)。 如果沒有提供依賴項數組,`useMemo`在每次渲染時都會計算新的值。 > `useCallback(fn, deps)`相當于`useMemo(() => fn, deps)`。 優化示例: ``` ... function Foo({bar, baz}) { useEffect(() => { const options = {bar, baz} buzz(options) }, [bar, baz]) return <div>foobar</div> } function Blub() { const bar = useCallback(() => {}, []) // 傳遞了`[]`作為`useCallback`的依賴列表。這確保了 callback 不會在再次渲染時改變,因此 React 不會在非必要的時候調用它。 const baz = useMemo(() => [1, 2, 3], []) // 沒有提供依賴項數組,`useMemo`在每次渲染時都會計算新的值 return <Foo bar={bar} baz={baz} /> } ... ``` 小結: * `useMemo`是在渲染期間執行的,所以`useMemo`中不要執行一些有副作用的操作。 * 沒有提供依賴項數組,`useMemo`在每次渲染時都會計算新的值,依賴數組是空數組的話,`useMemo`中的函數就只會執行一次。 * 在實現?useMemo?時,你需要問問自己:“這真的是一個代價高昂的函數嗎?”?代價高昂意味著它正在消耗大量資源(如內存)。如果在渲染時在函數中定義大量變量,則用?useMemo?進行記憶是非常有意義的。 > [什么時候使用 useMemo 和 useCallback-依賴列表](https://jancat.github.io/post/2019/translation-usememo-and-usecallback/#%E4%BE%9D%E8%B5%96%E5%88%97%E8%A1%A8) # Custom Hook 就是根據業務場景對以上四種 Hooks 進行組裝,從而得到滿足自己需求的鉤子。 1. 一個 JavaScript 函數 2. 名稱以`use` 開頭 3. 可以調用其他鉤子 > 自定義 hook 是一種自然遵循于 hook 設計的約定,而不是一個 React 特性 > 自定義 hook 沒有特別的語法,就是利用:`state`的改變會引發函數組件重新執行這一特性! 比如,我們要將我們上面的代碼功能封裝成 Hooks, 代碼如下 ``` import React, { useState, useEffect } from 'react' // 自定義的 Hook const usePerson = (name) => { const [loading, setLoading] = useState(true) const [person, setPerson] = useState({}) useEffect(() => { setLoading(true) setTimeout(()=> { setLoading(false) setPerson({name}) },2000) },[name]) return [loading,person] } const AsyncPage = ({name}) => { const [loading, person] = usePerson(name) return ( <> {loading?<p>Loading...</p>:<p>{person.name}</p>} </> ) } const PersonPage = () =>{ const [state, setState]=useState('') const changeName = (name) => { setState(name) } return ( <> <AsyncPage name={state}/> <button onClick={() => {changeName('名字1')}}>名字1</button> <button onClick={() => {changeName('名字2')}}>名字2</button> </> ) } export default PersonPage ``` 上面代碼中,我們將之前的例子封裝成了自己的 Hooks, 便于共享。其中,我們定義 `usePerson()` 為我們的自定義 Hooks,它接受一個字符串,返回一個數組,數組中包括兩個數據的狀態,之后我們在使用 `usePerson()` 時,會根據我們傳入的參數不同而返回不同的狀態(原理),然后很簡便的應用于我們的頁面中。 # 思考?? 不要在循環,條件或嵌套函數中調用 Hook。 相反,請始終在您的 React 函數的頂層使用 Hook。 通過遵循此規則,可以確保每次渲染組件時都以相同的順序調用 Hook。 這些是讓 React 在多個`useState`和`useEffect`調用之間正確保留 Hook 的狀態的原因。 > [https://reactjs.org/docs/hooks-rules.html#explanation](https://reactjs.org/docs/hooks-rules.html#explanation) > * **完全可選的。** 你無需重寫任何已有代碼就可以在一些組件中嘗試 Hook。但是如果你不想,你不必現在就去學習或使用 Hook。 > * **100% 向后兼容的。** Hook 不包含任何破壞性改動。 > * **現在可用。** Hook 已發布于 v16.8.0。 > * **沒有計劃從 React 中移除 class。** > * **Hook 不會影響你對 React 概念的理解。** 恰恰相反,Hook 為已知的 React 概念提供了更直接的 API:props, state,context,refs 以及生命周期。 使用 React Hook 規則: https://zh-hans.reactjs.org/docs/hooks-rules.html 使用 ESlint 插件: https://www.npmjs.com/package/eslint-plugin-react-hooks # 常見問題 [setInterval() 與 Hooks](https://overreacted.io/zh-hans/making-setinterval-declarative-with-react-hooks/) [Writing Redux-like simple middleware for React Hooks](https://medium.com/front-end-weekly/writing-redux-like-simple-middleware-for-react-hooks-b163724a7058) # 相關庫 [Awesome-React-Hooks](https://github.com/rehooks/awesome-react-hooks) ## Form [React Hook Form](https://react-hook-form.com/) Performant, flexible and extensible forms with easy-to-use validation ## React Hooks 庫 [usehooks.com](https://usehooks.com/) [react-query](https://github.com/tannerlinsley/react-query) [SWR](https://github.com/zeit/swr) [react-use](https://github.com/streamich/react-use) [豐富的 Hooks](https://github.com/umijs/hooks) [React Custom Hooks 最佳實踐](https://github.com/brickspert/blog/issues/31) # 參考 超性感的react hooks(六)自定義hooks的思維方式
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看