Render props、render callback 和高階組件皆可交換

讓 render-xxx 形式都能夠交換。

基礎

一切上面提到的三種形式都是為了處置懲罰 mixin 要處置懲罰的題目標。在我們繼承之前,我們來看一些例子。

假如你已控制這兩個觀點,能夠直接跳過這一節看後面的內容

Render Prop

起首,我們來寫一個組件來紀錄 count,並繪製 render prop 里的繪製都在 render 要領里調用了。

class CounterComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  update = type => {
    if (type === "Inc") {
      this.setState(({ count }) => ({ count: count + 1 }));
    } else if (type === "Dec") {
      this.setState(({ count }) => ({ count: count - 1 }));
    }
  };

  render() {
    return this.props.render({
      ...this.state,
      ...this.props,
      update: this.update
    });
  }
}

注重:callback 屬性也能夠叫個別的名字,不一定就是 render。只不過這個形式叫做 render prop。

接下來我們須要一個組件來把須要的內容繪製到屏幕上:

const Counter = ({ count, update }) => {
  <div>
    <button onClick={() => update("Inc")}>Inc</button>
    {count}
    <button onClick={() => update("Dec")}>Dev</button>
  </div>;
};

Counter組件接收 count 值和一個 update 要領,然後顯現一個增添、一個削減按鈕以及當前的 count 值。

末了我們能夠用CounterComponent組件來給Counter增添一些其他的功用:

render(
  <CounterComponent render={props => <Counter {...props} />>} />,
  document.getElementById('root')
);

高階組件

上文講解了 render prop 形式。如今來看看怎樣運用高階組件來到達一樣的目標。

const withCounter = Component =>
  class Hoc extends React.Component {
    constructor(props) {
      super(props);
      this.state = { count: 0 };
    }

    update = type => {
      if (type === "Inc") {
        this.setState(({ count }) => ({ count: count + 1 }));
      } else if (type === "Dec") {
        this.setState(({ count }) => ({ count: count - 1 }));
      }
    };

    render() {
      return <Component {...this.state} {} />
    }
  };

看上面的例子,我們能夠要把須要繪製的組件放到別的一個全新的組件內里去。在這個新的組件里包含了增強的 state 和 props 等內容。

const CounterExample = withCounter(Counter);
render(<CounterExample />, document.getElementById("root"));

現在我們已覆蓋了基礎的觀點。我們能夠運用差別的形式來到達雷同的目標。下面我們來關注一下怎樣讓這幾個形式到達交換的目標。

在 render props 和高階組件之間轉換

有的時刻你用的庫供應了一個高等組件,然則你最喜好的是經由過程JSX的體式格局來運用組件。有時會碰到一個供應了 render props 的庫,然則你喜好的是高階組件。一個很風趣的事實是這些形式能夠空想轉換。

我們來依據上面的例子來加一些要領能夠讓高階組件和 render props 形式能夠相互轉換。

fromHoc: HOC -> RenderProp
toHoc: RenderProp -> HOC

toHoc要領能夠歸結為:

toHoc: Render => Comp => props => (
  <Render {...Props} render={props => <Comp {...props} />} />
);

你也能夠看運用 Render Props來作為替換完成。

它會把一個 render prop 形式轉化為高階組件。

const withCounter = toHoc(CounterComponent);
const CounterExample = withCounter(Counter);

從高階組件轉化為 render prop 有一點貧苦。我們須要把一個 render prop 的組件傳入到高階組件里。多虧了 Brent Jackon 的這篇文章

fromHoc: hoc => {
  class Render extends React.Component {
    render() {
      return this.props.children(this.props);
    }
  }

  return hoc(Render);
};

或許,運用兩外一種不必 class 的體式格局。這次要謝謝 Rodrigo Pombo 的這個例子

fromHoc: hoc => hoc(props => props.render(props));

我們能夠寫一個輕量的 helper 要領來完成高階組件和 renderprops 的轉化。注重,我們也能夠在初始化 toHoc 要領的時刻運用別的的 render name,由於 render prop 能夠能有一個不一樣的名字,或許是一個子 prop。

const iso = {
  fromHoc: hoc => hoc(props => props.render(props)),
  toHoc: Render => Compo => props => (
    <Render {...props} render={props => <Comp {...props} />} />
  )
};

總結

Render prop,回調繪製和高階組件都是能夠交換的。大多數的時刻 render props 能夠滿足要求。然則你也能夠經由過程某些要領讓它在這些形式之間相互轉換。

非常謝謝 Brent Jackson,Kent C. Dodds 以及 Rodrigo Pombot 供應了fromHoc要領的完成,幫我們處理了不少的題目。

    原文作者:小紅星閃啊閃
    原文地址: https://segmentfault.com/a/1190000015455994
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞