React 高階組件(HOC)實踐

簡單來講高階組件(HOC)就是一個函數,它接受一個組件做爲參數而後返回一個新組件。HOC 主要用於組件之間邏輯複用。好比你寫了幾個組件,他們之間的邏輯幾乎相同,就能夠用 HOC 對邏輯進行封裝複用。javascript

本文主要分享:html

  • 如何封裝 HOC
  • HOC + 組合函數,處理多個 HOC 嵌套問題
  • HOC + 柯里化,封裝多參數的 HOC

如何封裝 HOC

這裏介紹幾個經常使用的 HOCjava

withLogger

咱們在調試代碼時,常常都須要打印 props,因此能夠將打印邏輯封裝起來。react

const withLogger = (prefix = "") => WrappedComponent => {
  const WithLogger = props => {
    console.log(`${prefix}[Props]:`, props);
    return <WrappedComponent {...props} />; }; return WithLogger; }; 複製代碼

使用:git

withLogger('這裏打印的是xxx')(Component)
複製代碼

withData

組件中的獲取數據的邏輯也能夠抽離成 HOC,須要傳入 url, param 兩個參數。github

import React, { Component } from "react";

const withData = (url, params) => WapperedComponent => {
  class WithData extends Component {
    state = {
      data: []
    };
    componentDidMount() {
      fetch(url, {body: JSON.stringify(params)})
         .then(response => response.json())
         .then(data => this.setState({ data }));
    }
    render() {
      return <WapperedComponent {...this.state} {...this.props} />; } } return WithData; }; 複製代碼

使用:編程

withData(
  url: 'https://jsonplaceholder.typicode.com/posts',
  params: {
    _limit: 10,
    page: 2
  }
)(Component)
複製代碼

withLoading

因爲數據請求是異步的,爲了避免讓用戶看到一片空白,當數據請求尚未返回時,展現 Loading 組件。json

const withLoading = Loading => WapperedComponent => {
  const WithLoading = props => {
    return props.data.length === 0 ? (
      <Loading />
    ) : (
      <WapperedComponent {...props} />
    );
  };
  return WithLoading;
};
複製代碼

使用:app

const Loading = () => <p>loading</p>;
withLoading(Loading)(Component)
複製代碼

如何處理多個 HOC 嵌套問題

若是一個組件,須要請求數據,在數據未返回時展現 loading,還須要打印 props, 那麼咱們須要將 withDatawithLoadingwithLogger 組合起來。異步

const Loading = () => <p>loading</p>;
withData(
  "https://jsonplaceholder.typicode.com/posts",
  {
    _limit: 10,
    page: 2
  }
})(
  withLogger('xxx')(
    withLoading(Loading)(Component)
  )
)
複製代碼

上面這種嵌套的方式可閱讀性不好,這裏用 compose 組合函數優化一下。

const compose = (...fns) => x => fns.reduceRight((x, fn) => fn(x), x);

const Loading = () => <p>loading</p>;
compose(
  withData(
    "https://jsonplaceholder.typicode.com/posts",
    {
      _limit: 10,
      page: 2
    }
  ),
  withLogger("這裏是xxx"),
  withLoading(Loading),
)(Component);
複製代碼

優化後的代碼明顯更爲易讀,固然若是你不習慣從下到上執行,你也能夠寫成 pipe 函數,只須要將 compose 函數中 reduceRight 方法改成 reduce 便可。

如何封裝多參數的 HOC

咱們注意到 withData 傳入了兩個參數,url 和 params,假如須要屢次調用 withData ,好比:

withData(
    "https://jsonplaceholder.typicode.com/posts",
    {
      _limit: 10,
    }
)
withData(
    "https://jsonplaceholder.typicode.com/posts",
    {
      _limit: 9,
    }
)
withData(
    "https://jsonplaceholder.typicode.com/posts",
    {
      _limit: 8,
    }
)
複製代碼

咱們發現每次調用的 url 都相同,這裏能夠用柯里化函數將參數封裝一下:

const curry = fn => {
  const loop = (...args) => args.length === fn.length
    ? fn(...args)
    : (...arg) => loop(...args,...arg)
  return loop
}

const withPostData = curry(withData)("https://jsonplaceholder.typicode.com/posts")

withPostData({_limit: 10})
withPostData({_limit: 9})
withPostData({_limit: 8})

複製代碼

同理咱們還能夠根據不一樣的 url 封裝成 withUserDatawithCommentData 等等。

總結

  1. 經過 HOC 將一些代碼邏輯封裝起來,可增長代碼的複用性,也方便後期維護。
  2. HOC + 組合函數,提高代碼可閱讀性。
  3. HOC + 柯里化,封裝多參數的 HOC,進一步增長代碼的複用性。

參考

相關文章
相關標籤/搜索