精讀《怎麼用 React Hooks 造輪子》

1 引言

上週的 精讀《React Hooks》 已經實現了對 React Hooks 的基本認知,也許你也看了 React Hooks 基本實現剖析(就是數組),但理解實現原理就能夠用好了嗎?學的是知識,而用的是技能,看別人的用法就像刷抖音同樣(哇,飯還能夠這樣吃?),你總會有新的收穫。css

這篇文章將這些知識實踐起來,看看廣大程序勞動人民是如何發掘 React Hooks 的潛力的(造什麼輪子)。html

首先,站在使用角度,要理解 React Hooks 的特色是 「很是方便的 Connect 一切」,因此不管是數據流、Network,或者是定時器均可以監聽,有一點 RXJS 的意味,也就是你能夠利用 React Hooks,將 React 組件打形成:任何事物的變化都是輸入源,當這些源變化時會從新觸發 React 組件的 render,你只須要挑選組件綁定哪些數據源(use 哪些 Hooks),而後只管寫 render 函數就好了!前端

2 精讀

參考了部分 React Hooks 組件後,筆者按照功能進行了一些分類。react

因爲 React Hooks 並非很是複雜,因此就不按照技術實現方式去分類了,畢竟技術總有一天會熟練,並且按照功能分類纔有持久的參考價值。git

DOM 反作用修改 / 監聽

作一個網頁,總有一些看上去和組件關係不大的麻煩事,好比修改頁面標題(切換頁面記得改爲默認標題)、監聽頁面大小變化(組件銷燬記得取消監聽)、斷網時提示(一層層裝飾器要堆成小山了)。而 React Hooks 特別擅長作這些事,造這種輪子,大小皆宜。github

因爲 React Hooks 下降了高階組件使用成本,那麼一套生命週期才能完成的 「雜耍」 將變得很是簡單。spring

下面舉幾個例子:json

修改頁面 title

效果:在組件裏調用 useDocumentTitle 函數便可設置頁面標題,且切換頁面時,頁面標題重置爲默認標題 「前端精讀」。redux

useDocumentTitle("我的中心");
複製代碼

實現:直接用 document.title 賦值,不能再簡單。在銷燬時再次給一個默認標題便可,這個簡單的函數能夠抽象在項目工具函數裏,每一個頁面組件都須要調用。數組

function useDocumentTitle(title) {
  useEffect(
    () => {
      document.title = title;
      return () => (document.title = "前端精讀");
    },
    [title]
  );
}
複製代碼

在線 Demo

監聽頁面大小變化,網絡是否斷開

效果:在組件調用 useWindowSize 時,能夠拿到頁面大小,而且在瀏覽器縮放時自動觸發組件更新。

const windowSize = useWindowSize();
return <div>頁面高度:{windowSize.innerWidth}</div>;
複製代碼

實現:和標題思路基本一致,此次從 window.innerHeight 等 API 直接拿到頁面寬高便可,注意此時能夠用 window.addEventListener('resize') 監聽頁面大小變化,此時調用 setValue 將會觸發調用自身的 UI 組件 rerender,就是這麼簡單!

最後注意在銷燬時,removeEventListener 註銷監聽。

function getSize() {
  return {
    innerHeight: window.innerHeight,
    innerWidth: window.innerWidth,
    outerHeight: window.outerHeight,
    outerWidth: window.outerWidth
  };
}

function useWindowSize() {
  let [windowSize, setWindowSize] = useState(getSize());

  function handleResize() {
    setWindowSize(getSize());
  }

  useEffect(() => {
    window.addEventListener("resize", handleResize);
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return windowSize;
}
複製代碼

在線 Demo

動態注入 css

效果:在頁面注入一段 class,而且當組件銷燬時,移除這個 class。

const className = useCss({
  color: "red"
});

return <div className={className}>Text.</div>;
複製代碼

實現:能夠看到,Hooks 方便的地方是在組件銷燬時移除反作用,因此咱們能夠安心的利用 Hooks 作一些反作用。注入 css 天然沒必要說了,而銷燬 css 只要找到注入的那段引用進行銷燬便可,具體能夠看這個 代碼片斷

DOM 反作用修改 / 監聽場景有一些現成的庫了,從名字上就能看出來用法:document-visibilitynetwork-statusonline-statuswindow-scroll-positionwindow-sizedocument-title

組件輔助

Hooks 還能夠加強組件能力,好比拿到並監聽組件運行時寬高等。

獲取組件寬高

效果:經過調用 useComponentSize 拿到某個組件 ref 實例的寬高,而且在寬高變化時,rerender 並拿到最新的寬高。

const ref = useRef(null);
let componentSize = useComponentSize(ref);

return (
  <>
    {componentSize.width}
    <textArea ref={ref} />
  </>
);
複製代碼

實現:和 DOM 監聽相似,此次換成了利用 ResizeObserver 對組件 ref 進行監聽,同時在組件銷燬時,銷燬監聽。

其本質仍是監聽一些反作用,但經過 ref 的傳遞,咱們能夠對組件粒度進行監聽和操做了。

useLayoutEffect(() => {
  handleResize();

  let resizeObserver = new ResizeObserver(() => handleResize());
  resizeObserver.observe(ref.current);

  return () => {
    resizeObserver.disconnect(ref.current);
    resizeObserver = null;
  };
}, []);
複製代碼

在線 Demo,對應組件 component-size

拿到組件 onChange 拋出的值

效果:經過 useInputValue() 拿到 Input 框當前用戶輸入的值,而不是手動監聽 onChange 再騰一個 otherInputValue 和一個回調函數把這一堆邏輯寫在無關的地方。

let name = useInputValue("Jamie");
// name = { value: 'Jamie', onChange: [Function] }
return <input {...name} />;
複製代碼

能夠看到,這樣不只沒有佔用組件本身的 state,也不須要手寫 onChange 回調函數進行處理,這些處理都壓縮成了一行 use hook。

實現:讀到這裏應該大體能夠猜到了,利用 useState 存儲組件的值,並拋出 valueonChange,監聽 onChange 並經過 setValue 修改 value, 就能夠在每次 onChange 時觸發調用組件的 rerender 了。

function useInputValue(initialValue) {
  let [value, setValue] = useState(initialValue);
  let onChange = useCallback(function(event) {
    setValue(event.currentTarget.value);
  }, []);

  return {
    value,
    onChange
  };
}
複製代碼

這裏要注意的是,咱們對組件加強時,組件的回調通常不須要銷燬監聽,並且僅需監聽一次,這與 DOM 監聽不一樣,所以大部分場景,咱們須要利用 useCallback 包裹,並傳一個空數組,來保證永遠只監聽一次,並且不須要在組件銷燬時註銷這個 callback。

在線 Demo,對應組件 input-value

作動畫

利用 React Hooks 作動畫,通常是拿到一些具備彈性變化的值,咱們能夠將值賦給進度條之類的組件,這樣其進度變化就符合某種動畫曲線。

在某個時間段內獲取 0-1 之間的值

這個是動畫最基本的概念,某個時間內拿到一個線性增加的值。

效果:經過 useRaf(t) 拿到 t 毫秒內不斷刷新的 0-1 之間的數字,期間組件會不斷刷新,但刷新頻率由 requestAnimationFrame 控制(不會卡頓 UI)。

const value = useRaf(1000);
複製代碼

實現:寫起來比較冗長,這裏簡單描述一下。利用 requestAnimationFrame 在給定時間內給出 0-1 之間的值,那每次刷新時,只要判斷當前刷新的時間點佔總時間的比例是多少,而後作分母,分子是 1 便可。

在線 Demo,對應組件 use-raf

彈性動畫

效果:經過 useSpring 拿到動畫值,組件以固定頻率刷新,而這個動畫值以彈性函數進行增減。

實際調用方式通常是,先經過 useState 拿到一個值,再經過動畫函數包住這個值,這樣組件就會從本來的刷新一次,變成刷新 N 次,拿到的值也隨着動畫函數的規則變化,最後這個值會穩定到最終的輸入值(如例子中的 50)。

const [target, setTarget] = useState(50);
const value = useSpring(target);

return <div onClick={() => setTarget(100)}>{value}</div>;
複製代碼

實現:爲了實現動畫效果,須要依賴 rebound 庫,它能夠實現將一個目標值拆解爲符合彈性動畫函數過程的功能,那咱們須要利用 React Hooks 作的就是在第一次接收到目標值是,調用 spring.setEndValue 來觸發動畫事件,並在 useEffect 裏作一次性監聽,再值變時從新 setValue 便可。

最神奇的 setTarget 聯動 useSpring 從新計算彈性動畫部分,是經過 useEffect 第二個參數實現的:

useEffect(
  () => {
    if (spring) {
      spring.setEndValue(targetValue);
    }
  },
  [targetValue]
);
複製代碼

也就是當目標值變化後,纔會進行新的一輪 rerender,因此 useSpring 並不須要監聽調用處的 setTarget,它只須要監聽 target 的變化便可,而巧妙利用 useEffect 的第二個參數能夠事半功倍。

在線 Demo

Tween 動畫

明白了彈性動畫原理,Tween 動畫就更簡單了。

效果:經過 useTween 拿到一個從 0 變化到 1 的值,這個值的動畫曲線是 tween。能夠看到,因爲取值範圍是固定的,因此咱們不須要給初始值了。

const value = useTween();
複製代碼

實現:經過 useRaf 拿到一個線性增加的值(區間也是 0 ~ 1),再經過 easing 庫將其映射到 0 ~ 1 到值便可。這裏用到了 hook 調用 hook 的聯動(經過 useRaf 驅動 useTween),還能夠在其餘地方觸類旁通。

const fn: Easing = easing[easingName];
const t = useRaf(ms, delay);

return fn(t);
複製代碼

發請求

利用 Hooks,能夠將任意請求 Promise 封裝爲帶有標準狀態的對象:loading、error、result。

通用 Http 封裝

效果:經過 useAsync 將一個 Promise 拆解爲 loading、error、result 三個對象。

const { loading, error, result } = useAsync(fetchUser, [id]);
複製代碼

實現:在 Promise 的初期設置 loading,結束後設置 result,若是出錯則設置 error,這裏能夠將請求對象包裝成 useAsyncState 來處理,這裏就不放出來了。

export function useAsync(asyncFunction) {
  const asyncState = useAsyncState(options);

  useEffect(() => {
    const promise = asyncFunction();
    asyncState.setLoading();
    promise.then(
      result => asyncState.setResult(result);,
      error => asyncState.setError(error);
    );
  }, params);
}
複製代碼

具體代碼能夠參考 react-async-hook,這個功能建議僅瞭解原理,具體實現由於有一些邊界狀況須要考慮,好比組件 isMounted 後才能相應請求結果。

Request Service

業務層通常會抽象一個 request service 作統一取數的抽象(好比統一 url,或者能夠統一換 socket 實現等等)。假如之前比較 low 的作法是:

async componentDidMount() {
  // setState: 改 isLoading state
  try {
    const data = await fetchUser()
    // setState: 改 isLoading、error、data
  } catch (error) {
    // setState: 改 isLoading、error
  }
}
複製代碼

後來把請求放在 redux 裏,經過 connect 注入的方式會稍微有些改觀:

@Connect(...)
class App extends React.PureComponent {
  public componentDidMount() {
    this.props.fetchUser()
  }

  public render() {
    // this.props.userData.isLoading | error | data
  }
}
複製代碼

最後會發現仍是 Hooks 簡潔明瞭:

function App() {
  const { isLoading, error, data } = useFetchUser();
}
複製代碼

useFetchUser 利用上面封裝的 useAsync 能夠很容易編寫:

const fetchUser = id =>
  fetch(`xxx`).then(result => {
    if (result.status !== 200) {
      throw new Error("bad status = " + result.status);
    }
    return result.json();
  });

function useFetchUser(id) {
  const asyncFetchUser = useAsync(fetchUser, id);
  return asyncUser;
}
複製代碼

填表單

React Hooks 特別適合作表單,尤爲是 antd form 若是支持 Hooks 版,那用起來會方便許多:

function App() {
  const { getFieldDecorator } = useAntdForm();

  return (
    <Form onSubmit={this.handleSubmit} className="login-form">
      <FormItem>
        {getFieldDecorator("userName", {
          rules: [{ required: true, message: "Please input your username!" }]
        })(
          <Input
            prefix={<Icon type="user" style={{ color: "rgba(0,0,0,.25)" }} />}
            placeholder="Username"
          />
        )}
      </FormItem>
      <FormItem>
        <Button type="primary" htmlType="submit" className="login-form-button">
          Log in
        </Button>
        Or <a href="">register now!</a>
      </FormItem>
    </Form>
  );
}
複製代碼

不過雖然如此,getFieldDecorator 仍是基於 RenderProps 思路的,完全的 Hooks 思路是利用以前說的 組件輔助方式,提供一個組件方法集,用解構方式傳給組件

Hooks 思惟的表單組件

效果:經過 useFormState 拿到表單值,而且提供一系列 組件輔助 方法控制組件狀態。

const [formState, { text, password }] = useFormState();
return (
  <form>
    <input {...text("username")} required />
    <input {...password("password")} required minLength={8} />
  </form>
);
複製代碼

上面能夠經過 formState 隨時拿到表單值,和一些校驗信息,經過 password("pwd") 傳給 input 組件,讓這個組件達到受控狀態,且輸入類型是 password 類型,表單 key 是 pwd。並且能夠看到使用的 form 是原生標籤,這種表單加強是至關解耦的。

實現:仔細觀察一下結構,不難發現,咱們只要結合 組件輔助 小節說的 「拿到組件 onChange 拋出的值」 一節的思路,就能輕鬆理解 textpassword 是如何做用於 input 組件,並拿到其輸入狀態

往簡單的來講,只要把這些狀態 Merge 起來,經過 useReducer 聚合到 formState 就能夠實現了。

爲了簡化,咱們只考慮對 input 的加強,源碼僅需 30 幾行:

export function useFormState(initialState) {
  const [state, setState] = useReducer(stateReducer, initialState || {});

  const createPropsGetter = type => (name, ownValue) => {
    const hasOwnValue = !!ownValue;
    const hasValueInState = state[name] !== undefined;

    function setInitialValue() {
      let value = "";
      setState({ [name]: value });
    }

    const inputProps = {
      name, // 給 input 添加 type: text or password
      get value() {
        if (!hasValueInState) {
          setInitialValue(); // 給初始化值
        }
        return hasValueInState ? state[name] : ""; // 賦值
      },
      onChange(e) {
        let { value } = e.target;
        setState({ [name]: value }); // 修改對應 Key 的值
      }
    };

    return inputProps;
  };

  const inputPropsCreators = ["text", "password"].reduce(
    (methods, type) => ({ ...methods, [type]: createPropsGetter(type) }),
    {}
  );

  return [
    { values: state }, // formState
    inputPropsCreators
  ];
}
複製代碼

上面 30 行代碼實現了對 input 標籤類型的設置,監聽 value onChange,最終聚合到大的 values 做爲 formState 返回。讀到這裏應該發現對 React Hooks 的應用都是萬變不離其宗的,特別是對組件信息的獲取,經過解構方式來作,Hooks 內部再作一下聚合,就完成表單組件基本功能了。

實際上一個完整的輪子還須要考慮 checkbox radio 的兼容,以及校驗問題,這些思路大同小異,具體源碼能夠看 react-use-form-state

模擬生命週期

有的時候 React15 的 API 仍是挺有用的,利用 React Hooks 幾乎能夠模擬出全套。

componentDidMount

效果:經過 useMount 拿到 mount 週期才執行的回調函數。

useMount(() => {
  // quite similar to `componentDidMount`
});
複製代碼

實現:componentDidMount 等價於 useEffect 的回調(僅執行一次時),所以直接把回調函數拋出來便可。

useEffect(() => void fn(), []);
複製代碼

componentWillUnmount

效果:經過 useUnmount 拿到 unmount 週期才執行的回調函數。

useUnmount(() => {
  // quite similar to `componentWillUnmount`
});
複製代碼

實現:componentWillUnmount 等價於 useEffect 的回調函數返回值(僅執行一次時),所以直接把回調函數返回值拋出來便可。

useEffect(() => fn, []);
複製代碼

componentDidUpdate

效果:經過 useUpdate 拿到 didUpdate 週期才執行的回調函數。

useUpdate(() => {
  // quite similar to `componentDidUpdate`
});
複製代碼

實現:componentDidUpdate 等價於 useMount 的邏輯每次執行,除了初始化第一次。所以採用 mouting flag(判斷初始狀態)+ 不加限制參數確保每次 rerender 都會執行便可。

const mounting = useRef(true);
useEffect(() => {
  if (mounting.current) {
    mounting.current = false;
  } else {
    fn();
  }
});
複製代碼

Force Update

效果:這個最有意思了,我但願拿到一個函數 update,每次調用就強制刷新當前組件。

const update = useUpdate();
複製代碼

實現:咱們知道 useState 下標爲 1 的項是用來更新數據的,並且就算數據沒有變化,調用了也會刷新組件,因此咱們能夠把返回一個沒有修改數值的 setValue,這樣它的功能就僅剩下刷新組件了。

const useUpdate = () => useState(0)[1];
複製代碼

對於 getSnapshotBeforeUpdate, getDerivedStateFromError, componentDidCatch 目前 Hooks 是沒法模擬的。

isMounted

好久之前 React 是提供過這個 API 的,後來移除了,緣由是能夠經過 componentWillMountcomponentWillUnmount 推導。自從有了 React Hooks,支持 isMount 簡直是分分鐘的事。

效果:經過 useIsMounted 拿到 isMounted 狀態。

const isMounted = useIsMounted();
複製代碼

實現:看到這裏的話,應該已經很熟悉這個套路了,useEffect 第一次調用時賦值爲 true,組件銷燬時返回 false,注意這裏能夠加第二個參數爲空數組來優化性能。

const [isMount, setIsMount] = useState(false);
useEffect(() => {
  if (!isMount) {
    setIsMount(true);
  }
  return () => setIsMount(false);
}, []);
return isMount;
複製代碼

在線 Demo

存數據

上一篇提到過 React Hooks 內置的 useReducer 能夠模擬 Redux 的 reducer 行爲,那惟一須要補充的就是將數據持久化。咱們考慮最小實現,也就是全局 Store + Provider 部分。

全局 Store

效果:經過 createStore 建立一個全局 Store,再經過 StoreProviderstore 注入到子組件的 context 中,最終經過兩個 Hooks 進行獲取與操做:useStoreuseAction

const store = createStore({
  user: {
    name: "小明",
    setName: (state, payload) => {
      state.name = payload;
    }
  }
});

const App = () => (
  <StoreProvider store={store}>
    <YourApp />
  </StoreProvider>
);

function YourApp() {
  const userName = useStore(state => state.user.name);
  const setName = userAction(dispatch => dispatch.user.setName);
}
複製代碼

實現:這個例子的實現能夠單獨拎出一篇文章了,因此筆者從存數據的角度剖析一下 StoreProvider 的實現。

對,Hooks 並不解決 Provider 的問題,因此全局狀態必須有 Provider,但這個 Provider 能夠利用 React 內置的 createContext 簡單搞定:

const StoreContext = createContext();

const StoreProvider = ({ children, store }) => (
  <StoreContext.Provider value={store}>{children}</StoreContext.Provider>
);
複製代碼

剩下就是 useStore 怎麼取到持久化 Store 的問題了,這裏利用 useContext 和剛纔建立的 Context 對象:

const store = useContext(StoreContext);
return store;
複製代碼

更多源碼能夠參考 easy-peasy,這個庫基於 redux 編寫,提供了一套 Hooks API。

封裝原有庫

是否是 React Hooks 出現後,全部的庫都要重寫一次?固然不是,咱們看看其餘庫如何作改造。

RenderProps to Hooks

這裏拿 react-powerplug 舉例。

好比有一個 renderProps 庫,但願改形成 Hooks 的用法:

import { Toggle } from 'react-powerplug'

function App() {
  return (
    <Toggle initial={true}>
      {({ on, toggle }) => (
        <Checkbox checked={on} onChange={toggle} />
      )}
    </Toggle>
  )
}
↓ ↓ ↓ ↓ ↓ ↓
import { useToggle } from 'react-powerhooks'

function App() {
  const [on, toggle] = useToggle()
  return <Checkbox checked={on} onChange={toggle} />
}
複製代碼

效果:假如我是 react-powerplug 的維護者,怎麼樣最小成本支持 React Hook? 說實話這個沒辦法一步作到,但能夠經過兩步實現。

export function Toggle() {
  // 這是 Toggle 的源碼
  // balabalabala..
}

const App = wrap(() => {
  // 第一步:包 wrap
  const [on, toggle] = useRenderProps(Toggle); // 第二步:包 useRenderProps
});
複製代碼

實現:首先解釋一下爲何要包兩層,首先 Hooks 必須遵循 React 的規範,咱們必須寫一個 useRenderProps 函數以符合 Hooks 的格式,**那問題是如何拿到 Toggle 給 render 的 ontoggle?**正常方式應該拿不到,因此退而求其次,將 useRenderProps 拿到的 Toggle 傳給 wrapwrap 構造 RenderProps 執行環境拿到 ontoggle 後,調用 useRenderProps 內部的 setArgs 函數,讓 const [on, toggle] = useRenderProps(Toggle) 實現曲線救國。

const wrappers = []; // 全局存儲 wrappers

export const useRenderProps = (WrapperComponent, wrapperProps) => {
  const [args, setArgs] = useState([]);
  const ref = useRef({});
  if (!ref.current.initialized) {
    wrappers.push({
      WrapperComponent,
      wrapperProps,
      setArgs
    });
  }
  useEffect(() => {
    ref.current.initialized = true;
  }, []);
  return args; // 經過下面 wrap 調用 setArgs 獲取值。
};
複製代碼

因爲 useRenderProps 會先於 wrap 執行,因此 wrappers 會先拿到 Toggle,wrap 執行時直接調用 wrappers.pop() 便可拿到 Toggle 對象。而後構造出 RenderProps 的執行環境便可:

export const wrap = FunctionComponent => props => {
  const element = FunctionComponent(props);
  const ref = useRef({ wrapper: wrappers.pop() }); // 拿到 useRenderProps 提供的 Toggle
  const { WrapperComponent, wrapperProps } = ref.current.wrapper;
  return createElement(WrapperComponent, wrapperProps, (...args) => {
    // WrapperComponent => Toggle,這一步是在構造 RenderProps 執行環境
    if (!ref.current.processed) {
      ref.current.wrapper.setArgs(args); // 拿到 on、toggle 後,經過 setArgs 傳給上面的 args。
      ref.current.processed = true;
    } else {
      ref.current.processed = false;
    }
    return element;
  });
};
複製代碼

以上實現方案參考 react-hooks-render-props,有需求要能夠拿過來直接用,不過實現思路能夠參考,做者的腦洞挺大。

Hooks to RenderProps

好吧,若是但願 Hooks 支持 RenderProps,那必定是但願同時支持這兩套語法。

效果:一套代碼同時支持 Hooks 和 RenderProps。

實現:其實 Hooks 封裝爲 RenderProps 最方便,所以咱們使用 Hooks 寫核心的代碼,假設咱們寫一個最簡單的 Toggle

const useToggle = initialValue => {
  const [on, setOn] = useState(initialValue);
  return {
    on,
    toggle: () => setOn(!on)
  };
};
複製代碼

在線 Demo

而後經過 render-props 這個庫能夠輕鬆封裝出 RenderProps 組件:

const Toggle = ({ initialValue, children, render = children }) =>
  renderProps(render, useToggle(initialValue));
複製代碼

在線 Demo

其實 renderProps 這個組件的第二個參數,在 Class 形式 React 組件時,接收的是 this.state,如今咱們改爲 useToggle 返回的對象,也能夠理解爲 state,利用 Hooks 機制驅動 Toggle 組件 rerender,從而讓子組件 rerender。

封裝本來對 setState 加強的庫

Hooks 也特別適合封裝本來就做用於 setState 的庫,好比 immer

useState 雖然不是 setState,但卻能夠理解爲控制高階組件的 setState,咱們徹底能夠封裝一個自定義的 useState,而後內置對 setState 的優化。

好比 immer 的語法是經過 produce 包裝,將 mutable 代碼經過 Proxy 代理爲 immutable:

const nextState = produce(baseState, draftState => {
  draftState.push({ todo: "Tweet about it" });
  draftState[1].done = true;
});
複製代碼

那這個 produce 就能夠經過封裝一個 useImmer 來隱藏掉:

function useImmer(initialValue) {
  const [val, updateValue] = React.useState(initialValue);
  return [
    val,
    updater => {
      updateValue(produce(updater));
    }
  ];
}
複製代碼

使用方式:

const [value, setValue] = useImmer({ a: 1 });

value(obj => (obj.a = 2)); // immutable
複製代碼

3 總結

本文列出了 React Hooks 的如下幾種使用方式以及實現思路:

  • DOM 反作用修改 / 監聽。
  • 組件輔助。
  • 作動畫。
  • 發請求。
  • 填表單。
  • 模擬生命週期。
  • 存數據。
  • 封裝原有庫。

歡迎你們的持續補充。

4 更多討論

討論地址是:精讀《怎麼用 React Hooks 造輪子》 · Issue #112 · dt-fe/weekly

若是你想參與討論,請點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。

相關文章
相關標籤/搜索