原文鏈接: https://medium.com/@jrwebdev/...
和之前的文章一樣,本文也要求你對render props有一些知識背景,如果沒有官方文檔可能會對你有很大的幫助。本文將會使用函數作為children的render props模式以及結合React的context API來作為例子。如果你想使用類似于render這樣子的render props,那也只需要把下面例子的children作為你要渲染的props即可。
為了展示render props,我們將要重寫之前文章的makeCounter HOC。這里先展示HOC的版本:
export interface InjectedCounterProps { value: number; onIncrement(): void; onDecrement(): void; } interface MakeCounterProps { minValue?: number; maxValue?: number; } interface MakeCounterState { value: number; } const makeCounter =( Component: React.ComponentType
) => class MakeCounter extends React.Component< Subtract
& MakeCounterProps, MakeCounterState > { state: MakeCounterState = { value: 0, }; increment = () => { this.setState(prevState => ({ value: prevState.value === this.props.maxValue ? prevState.value : prevState.value + 1, })); }; decrement = () => { this.setState(prevState => ({ value: prevState.value === this.props.minValue ? prevState.value : prevState.value - 1, })); }; render() { const { minValue, maxValue, ...props } = this.props; return (
); } };
HOC向組件注入了value和兩個回調函數(onIncrement 和 onDecrement),此外還在HOC內部使用minValue和maxValue兩個props而沒有傳遞給組件。我們討論了如果組件需要知道這些值,如何不傳遞props可能會出現問題,并且如果使用多個HOC包裝組件,注入的props的命名也可能與其他HOC注入的props沖突。
makeCounter HOC將會被像下面這樣重寫:
interface InjectedCounterProps { value: number; onIncrement(): void; onDecrement(): void; } interface MakeCounterProps { minValue?: number; maxValue?: number; children(props: InjectedCounterProps): JSX.Element; } interface MakeCounterState { value: number; } class MakeCounter extends React.Component{ state: MakeCounterState = { value: 0, }; increment = () => { this.setState(prevState => ({ value: prevState.value === this.props.maxValue ? prevState.value : prevState.value + 1, })); }; decrement = () => { this.setState(prevState => ({ value: prevState.value === this.props.minValue ? prevState.value : prevState.value - 1, })); }; render() { return this.props.children({ value: this.state.value, onIncrement: this.increment, onDecrement: this.decrement, }); } }
這里有一些需要注意的變化。首先,injectedCounterProps被保留,因為我們需要定義一個props的interface在render props函數調用上而不是傳遞給組件的props(和HOC一樣)。MakeCounter(MakeCounterProps)的props已經改變,加上以下內容:
children(props: InjectedCounterProps): JSX.Element;
這是render prop,然后組件內需要一個函數帶上注入的props并返回JSX element。下面是它用來突出顯示這一點的示例:
interface CounterProps { style: React.CSSProperties; minValue?: number; maxValue?: number; } const Counter = (props: CounterProps) => ({injectedProps => ( );{injectedProps.value})}
MakeCounter自己的組件聲明變得簡單多了;它不再被包裝在函數中,因為它不再是臨時的,輸入也更加簡單,不需要泛型、做差值和類型的交集。它只有簡單的MakeCounterProps和MakeCounterState,就像其他任何組成部分一樣:
class MakeCounter extends React.Component< MakeCounterProps, MakeCounterState >
最后,render()的工作也變少了;它只是一個函數調用并帶上注入的props-不需要破壞和對象的props擴展運算符展開了!
return this.props.children({ value: this.state.value, onIncrement: this.increment, onDecrement: this.decrement, });
然后,render prop組件允許對props的命名和在使用的靈活性上進行更多的控制,這是和HOC等效的一個問題:
interface CounterProps { style: React.CSSProperties; value: number; minCounterValue?: number; maxCounterValue?: number; } const Counter = (props: CounterProps) => ({injectedProps => ( );)}Some other value: {props.value}{injectedProps.value}{props.minCounterValue !== undefined ? (Min value: {props.minCounterValue}) : null} {props.maxCounterValue !== undefined ? (Max value: {props.maxCounterValue}) : null}
有了所有這些好處,特別是更簡單的輸入,那么為什么不一直使用render props呢?當然可以,這樣做不會有任何問題,但要注意render props組件的一些問題。
首先,這里有一個關注點以外的問題;MakeCounter組件現在被放在了Counter組件內而不是包裝了它,這使得隔離測試這兩個組件更加困難。其次,由于props被注入到組件的渲染函數中,因此不能在生命周期方法中使用它們(前提是計數器被更改為類組件)。
這兩個問題都很容易解決,因為您可以使用render props組件簡單地生成一個新組件:
interface CounterProps extends InjectedCounterProps { style: React.CSSProperties; } const Counter = (props: CounterProps) => ({props.value}); interface WrappedCounterProps extends CounterProps { minValue?: number; maxValue?: number; } const WrappedCounter = ({ minValue, maxValue, ...props }: WrappedCounterProps) => ({injectedProps => );}
另一個問題是,一般來說,它不太方便,現在使用者需要編寫很多樣板文件,特別是如果他們只想將組件包裝在一個多帶帶的臨時文件中并按原樣使用props。這可以通過從render props組件生成HOC來補救:
import { Subtract, Omit } from "utility-types"; import MakeCounter, { MakeCounterProps, InjectedCounterProps } from "./MakeCounter"; type MakeCounterHocProps = Omit; const makeCounter = ( Component: React.ComponentType
): React.SFC
& MakeCounterHocProps> => ({ minValue, maxValue, ...props }: MakeCounterHocProps) => ( {injectedProps => );}
在這里,上一篇文章的技術,以及render props組件的現有類型,被用來生成HOC。這里唯一需要注意的是,我們必須從HOC的props中移除render prop(children),以便在使用時不暴露它:
type MakeCounterHocProps = Omit;
最后,HOC和render props組件之間的權衡歸結為靈活性和便利性。這可以通過首先編寫render props組件,然后從中生成HOC來解決,這使使用者能夠在兩者之間進行選擇。這種方法在可重用組件庫中越來越常見,例如優秀的render-fns庫。
就TypeScript而言,毫無疑問,hocs的類型定義要困難得多;盡管通過這兩篇文章中的示例,它表明這種負擔是由HOC的提供者而不是使用者承擔的。在使用方面,可以認為使用HOC比使用render props組件更容易。
在react v16.8.0之前,我建議使用render props組件以提高鍵入的靈活性和簡單性,如果需要,例如構建可重用的組件庫,或者對于簡單在項目中使用的render props組件,我將僅從中生成HOC。在react v16.8.0中釋放react hook之后,我強烈建議在可能的情況下對兩個高階組件或render props使用它們,因為它們的類型更簡單。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/103646.html
摘要:原文鏈接高階組件在中是組件復用的一個強大工具。在本文中,高階組件將會被分為兩種基本模式,我們將其命名為和用附加的功能來包裹組件。這里我們使用泛型表示傳遞到的組件的。在這里,我們定義從返回的組件,并指定該組件將包括傳入組件的和的。 原文鏈接:https://medium.com/@jrwebdev/... 高階組件(HOCs)在React中是組件復用的一個強大工具。但是,經常有開發者在...
摘要:致力于為應用提供一個類型安全表達力強可組合的狀態管理方案。是一組的命名空間。是內置組件的鏡像,但允許組件的額外接受類型的數據。這次內容更新,是由組件處理的。這些小的組件不必知道所有的應用狀態數據。這是因為大部分對的研究來自于。 Focal Focal 致力于為 React 應用提供一個類型安全、表達力強、可組合的狀態管理方案。 用一個不可變的 (immutable) 、響應式的 (o...
摘要:現已存在許多成熟的狀態管理解決方案,還有基于的但對于我個人來說,理想的狀態管理工具只需同時滿足兩個特點簡單易用,并且適合中大型項目完美地支持要做到這兩點其實并不簡單。所以我決定自己造一個可能是基于和最好的狀態管理工具 現已存在許多成熟的狀態管理解決方案:Redux、Mobx、Mobx-state-tree,還有基于 Redux 的 Dva.js、Rematch... 但對于我個人來說,...
摘要:近兩年來一直在關注開發,最近也開始全面應用。首先,我們從無狀態組件開始。渲染回調模式有一種重用組件邏輯的設計方式是把組件的寫成渲染回調函數或者暴露一個函數屬性出來。最后,我們將這個回調函數的參數聲明為一個獨立的類型。 近兩年來一直在關注 React 開發,最近也開始全面應用 TypeScript 。國內有很多講解 React 和 TypeScript 的教程,但如何將 TypeScri...
閱讀 1017·2021-10-27 14:15
閱讀 2773·2021-10-25 09:45
閱讀 1938·2021-09-02 09:45
閱讀 3363·2019-08-30 15:55
閱讀 1806·2019-08-29 16:05
閱讀 3199·2019-08-28 18:13
閱讀 3112·2019-08-26 13:58
閱讀 448·2019-08-26 12:01