SlideShare a Scribd company logo
HigherOrder(Components)
render={props}
> whoami
Nitish Phanse
@nitish24p
Builds stuff @ KyePot
UI = f(Components)
Higher Order Functions
Higher Order Functions
A function which takes one or more
arguments and returns a functions
function multiply() {
}
function multiply(firstNumber) {
return function(secondNumber) {
return firstNumber * secondNumber
}
}
multiply(3)(4)
throttle = (callback: Function, wait: number) => {
};
throttle = (callback: Function, wait: number) => {
let time = Date.now();
return function() {
};
};
throttle = (callback: Function, wait: number) => {
let time = Date.now();
return function() {
if (time + wait - Date.now() < 0) {
callback.apply(this, arguments);
time = Date.now();
}
};
};
throttle = (callback: Function, wait: number) => {
let time = Date.now();
return function() {
if (time + wait - Date.now() < 0) {
callback.apply(this, arguments);
time = Date.now();
}
};
};
<Input onChange={this.throttle(this.handleInputChange, 500)} />
Higher Order Functions
A function which takes one or more
arguments and returns a functions
Higher Order Functions
A function which takes one or more
arguments and returns a functions
Component
Higher Order Functions
A function which takes one or more
arguments and returns a functions
Component
A function which takes a component as an
argument and returns a new component
function myHigherOrderComponent(Component) {
}
function myHigherOrderComponent(Component) {
return class extends React.Component {
}
}
function myHigherOrderComponent(Component) {
return class extends React.Component {
render() {
return <Component />
}
}
}
function myHigherOrderComponent(Component) {
return class extends React.Component {
render() {
return <Component {...this.props}/>
}
}
}
function myHigherOrderComponent(Component) {
return class extends React.Component {
render() {
return <Component {...this.props}/>
}
}
}
export default myHigherOrderComponent(App);

<EnhancedApp foo={bar}/>
Alternative to Mixins Pattern
Encapsulates Logic that can be shared easily
Access data from any part of the component life cycle
Some real world use cases please
Code Splitting
function asyncComponent(importComponent: Function, LoadingComponent: Function) {
class AsyncComponent extends Component {
}
return AsyncComponent;
}
function asyncComponent(importComponent: Function, LoadingComponent: Function) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
}
return AsyncComponent;
}
function asyncComponent(importComponent: Function, LoadingComponent: Function) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : <LoadingComponent />;
}
}
return AsyncComponent;
}
function asyncComponent(importComponent: Function, LoadingComponent: Function) {
class AsyncComponent extends Component {
constructor(props) {
super(props);
this.state = {
component: null
};
}
async componentDidMount() {
const { default: component } = await importComponent();
this.setState({
component: component
});
}
render() {
const C = this.state.component;
return C ? <C {...this.props} /> : <LoadingComponent />;
}
}
return AsyncComponent;
}
class App extends Component {
render() {
<div>
<Switch>
</Switch>
</div>
}
}
const Products = asyncComponent(() => import('./pages/Products'), LoaderComponent);
const HomePage = asyncComponent(() => import('./pages/HomePage'), LoaderComponent);
class App extends Component {
render() {
<div>
<Switch>
<Route exact path={'/'} component={HomePage} />
<Route exact path={'/products'} component={Products} />
</Switch>
</div>
}
}
Server Side Rendering
const wrapComponentWithData = (WrappedComponent) => {
return class CustomComponent extends React.Component {
render() {
return <WrappedComponent {...this.props} />;
}
};
};
const wrapComponentWithData = (WrappedComponent, InitialData) => {
return class CustomComponent extends React.Component {
render() {
return <WrappedComponent {...InitialData} {...this.props} />;
}
};
};
const wrapComponentWithData = (WrappedComponent, InitialData) => {
return class CustomComponent extends React.Component {
render() {
return <WrappedComponent {...InitialData} {...this.props} />;
}
};
};
class App extends Component {
render() {
const data = { this.props }
return (
<div>
<Switch>
<Route exact path={'/'}
component={wrapComponentWithData(Homepage, data)} />
<Route exact path={'/products'}
component={wrapComponentWithData(Products, data)} />
</Switch>
</div>
);
}
}
Data Tracking
import TrackerLib from 'tracker.js'
const withTracking = (Component, pageName, eventObject) => {
};
import TrackerLib from 'tracker.js'
const withTracking = (Component, pageName, eventObject) => {
return class CustomComponent extends React.Component {
render() {
return <Component {...this.props} />;
}
};
};
import TrackerLib from 'tracker.js'
const withTracking = (Component, pageName, eventObject) => {
return class CustomComponent extends React.Component {
componentDidMount() {
TrackerLib.event(pageName, ...eventObject)
}
render() {
return <Component {...this.props} />;
}
};
};
import TrackerLib from 'tracker.js'
const withTracking = (Component, pageName, eventObject) => {
return class CustomComponent extends React.Component {
componentDidMount() {
TrackerLib.event(pageName, ...eventObject)
}
render() {
return <Component {...this.props} />;
}
};
};
export default withTracking(HomePage, 'Home Page', {});
Component Logger
function componentLogger(WrappedComponent) {
return class extends React.Component {
render() {
return <WrappedComponent {...this.props} />;
}
}
}
function componentLogger(WrappedComponent) {
return class extends React.Component {
componentWillReceiveProps(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
}
function componentLogger(WrappedComponent) {
return class extends React.Component {
componentWillReceiveProps(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
}
export default componentLogger(HomePage);
Some Handy Tips
Some Handy Tips
Some Handy Tips
Avoid using HOCs inside the render method
Avoid using HOCs inside the render method
Some Handy Tips
render() {
const EnhancedComponent = enhance(MyComponent);
return <EnhancedComponent />;
}
Some Handy Tips
render() {
const EnhancedComponent = enhance(MyComponent);
return <EnhancedComponent />;
}
Avoid using HOCs inside the render method
Refs Aren’t Passed Through
Some Handy Tips
Refs Aren’t Passed Through
Some Handy Tips
function Field({ inputRef, ...rest }) {
return <input ref={inputRef} {...rest} />;
}
Refs Aren’t Passed Through
Some Handy Tips
function Field({ inputRef, ...rest }) {
return <input ref={inputRef} {...rest} />;
}
const EnhancedField = enhance(Field);
<EnhancedField
inputRef={(inputEl) => {
this.inputEl = inputEl
}}
/>
Refs Aren’t Passed Through
Some Handy Tips
function Field({ inputRef, ...rest }) {
return <input ref={inputRef} {...rest} />;
}
const EnhancedField = enhance(Field);
<EnhancedField
inputRef={(inputEl) => {
this.inputEl = inputEl
}}
/>
// Inside Your HOC
this.inputEl.focus();
Common examples of HOC
connect of Redux
createContainer of Relay
Downshift
UrQl
Breathe
Breathe.
Breathe..
Breathe…
Props
A prop is an object for passing data to a
component
Render Prop
A render prop is a function prop that a
component uses to know what to render
class Posts extends React.Component {
state = {
posts: getInitialPostData()
}
render() {
return (
<div>
{this.state.posts.map(post =>
<Post post={post} key={post.id}/>)}
</div>
)
}
}
class Posts extends React.Component {
state = {
posts: getInitialPostData()
}
render() {
return (
<div>
{this.state.posts.map(post =>
<Post post={post} key={post.id}/>)}
</div>
)
}
}
<Posts />
class Posts extends React.Component {
state = {
posts: getInitialPostData()
}
render() {
return (
<div>
{this.state.posts.map(post =>
<Post post={post} key={post.id}/>)}
</div>
)
}
}
class Posts extends React.Component {
state = {
posts: getInitialPostData()
}
render() {
return (
<div>
{this.props.render(this.state)}
</div>
)
}
}
class Posts extends React.Component {
state = {
posts: getInitialPostData()
}
render() {
return (
<div>
{this.props.render(this.state)}
</div>
)
}
}
<Posts
render={({ posts }) =>
posts.map(post => <Post post={post} />)}
/>
Can i use children ???
🤔
class Posts extends React.Component {
state = {
posts: getInitialPostData()
}
render() {
return (
<div>
{this.props.children(this.state)}
</div>
)
}
}
class Posts extends React.Component {
state = {
posts: getInitialPostData()
}
render() {
return (
<div>
{this.props.children(this.state)}
</div>
)
}
}
<Posts>
{
({ posts }) =>
posts.map(post => <Post post={post} />)
}
</Posts>
Fully declarative approach using props
No props naming collision
Eases reusability of components
Where can i use a Render prop?
Async List Fetching
class List extends React.Component {
state = {
list: [],
isLoading: false,
};
componentDidMount() {
this.setState({ isLoading: true }, this.fetchData);
}
fetchData = async () => {
const res = await fetch(this.props.url);
const json = await res.json();
this.setState({
list: json,
isLoading: false,
});
}
}
class List extends React.Component {
state = {
list: [],
isLoading: false,
};
componentDidMount() {
this.setState({ isLoading: true }, this.fetchData);
}
fetchData = async () => {
const res = await fetch(this.props.url);
const json = await res.json();
this.setState({
list: json,
isLoading: false,
});
}
render() {
return this.props.render(this.state);
}
}
<List
url="https://api.github.com/users/nitish24p/repos"
render={
}/>
<List
url="https://api.github.com/users/nitish24p/repos"
render={({ list, isLoading }) => (
<div>
<h2>My repos</h2>
{isLoading && <h2>Loading...</h2>}
<ul>
{list.length > 0 && list.map(repo => (
<li key={repo.id}>
{repo.full_name}
</li>
))}
</ul>
</div>
)} />
Geolocation
class Location extends Component {
}
class Location extends Component {
state = {
latitude: undefined,
longititude: undefined
}
fetchGeoLocation = async () => {
const res = await fetch("api/url");
const json = await res.json();
this.setState({
latitude: json.lat,
longitude: json.long,
});
}
}
class Location extends Component {
state = {
latitude: undefined,
longititude: undefined
}
fetchGeoLocation = async () => {
const res = await fetch("api/url");
const json = await res.json();
this.setState({
latitude: json.lat,
longitude: json.long,
});
}
render() {
const { latitude, longitude } = this.state;
return this.props.children({
latitude,
longitude,
fetchLocation: this.fetchGeoLocation
});
}
}
<Location>
</Location>
<Location>
{({ latitude, longitude, fetchLocation }) => {
}}
</Location>
<Location>
{({ latitude, longitude, fetchLocation }) => {
if (latitude && longitude) {
return <Map marker={latitude, longitude}/>
}
return <Button label='Get Location'
onClick={fetchLocation}/>
}}
</Location>
Handy Tip
Handy Tip
Be careful when using Render Props with
React.PureComponent
Handy Tip
Be careful when using Render Props with
React.PureComponent
Use function reference instead of arrow fn
Handy Tip
this.renderPosts = ({ posts }) => {
return posts.map(post => <Post post={post} />
}
<Posts
render={this.renderPosts}
/>
Common examples of render props
withRouter of React Router
Motion of React Motion
Downshift
UrQl
Can i create a HOC using a Render Prop
Can i create a HOC using a Render Prop
Can i create a HOC using a Render Prop
const withRouter = (Component) => {
const C = (props) => {
const { wrappedComponentRef, ...remainingProps } = props
return (
<Route render={routeComponentProps => (
<Component {...remainingProps}
{...routeComponentProps} ref={wrappedComponentRef} />
)} />
)
}
...
}
function HigherOrderCompCounter(Component) {
return class extends React.Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render () {
return <Component counter={this.state.counter}
{...this.props}/>
}
}
}
const HOCCounter =
HigherOrderCompCounter(CounterComponent);
<HOCCounter />
class Counter extends Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render() {
return this.props.children(this.state);
}
}
<Counter>
{({ counter }) => <h1>{counter}</h1>}
</Counter>
Higher order Component Render Prop
const CounterComponent = ({ counter }) =>
<h1>{counter}</h1>
function HigherOrderCompCounter(Component) {
return class extends React.Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render () {
return <Component counter={this.state.counter}
{...this.props}/>
}
}
}
const HOCCounter =
HigherOrderCompCounter(CounterComponent);
<HOCCounter />
class Counter extends Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render() {
return this.props.children(this.state);
}
}
<Counter>
{({ counter }) => <h1>{counter}</h1>}
</Counter>
Higher order Component Render Prop
const CounterComponent = ({ counter }) =>
<h1>{counter}</h1>
function HigherOrderCompCounter(Component) {
return class extends React.Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render () {
return <Component counter={this.state.counter}
{...this.props}/>
}
}
}
const HOCCounter =
HigherOrderCompCounter(CounterComponent);
<HOCCounter />
class Counter extends Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render() {
return this.props.children(this.state);
}
}
<Counter>
{({ counter }) => <h1>{counter}</h1>}
</Counter>
Higher order Component Render Prop
const CounterComponent = ({ counter }) =>
<h1>{counter}</h1>
function HigherOrderCompCounter(Component) {
return class extends React.Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render () {
return <Component counter={this.state.counter}
{...this.props}/>
}
}
}
const HOCCounter =
HigherOrderCompCounter(CounterComponent);
<HOCCounter />
class Counter extends Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render() {
return this.props.children(this.state);
}
}
<Counter>
{({ counter }) => <h1>{counter}</h1>}
</Counter>
Higher order Component Render Prop
const CounterComponent = ({ counter }) =>
<h1>{counter}</h1>
function HigherOrderCompCounter(Component) {
return class extends React.Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render () {
return <Component counter={this.state.counter}
{...this.props}/>
}
}
}
const HOCCounter =
HigherOrderCompCounter(CounterComponent);
<HOCCounter />
class Counter extends Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render() {
return this.props.children(this.state);
}
}
<Counter>
{({ counter }) => <h1>{counter}</h1>}
</Counter>
Higher order Component Render Prop
const CounterComponent = ({ counter }) =>
<h1>{counter}</h1>
function HigherOrderCompCounter(Component) {
return class extends React.Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render () {
return <Component counter={this.state.counter}
{...this.props}/>
}
}
}
const HOCCounter =
HigherOrderCompCounter(CounterComponent);
<HOCCounter />
class Counter extends Component {
state = {
counter: 0
}
componentDidMount() {
setInterval(() => {
this.setState((prevState) =>
({counter: prevState.counter + 1}));
}, 1000)
}
render() {
return this.props.children(this.state);
}
}
<Counter>
{({ counter }) => <h1>{counter}</h1>}
</Counter>
Higher order Component Render Prop
const CounterComponent = ({ counter }) =>
<h1>{counter}</h1>
Thank you

More Related Content

What's hot (20)

PPTX
reactJS
Syam Santhosh
 
PDF
C# コーディングガイドライン 2013/02/26
Yoshihisa Ozaki
 
PPTX
Introduction to React JS for beginners
Varun Raj
 
PPTX
React render props
Saikat Samanta
 
PDF
Introduction to Spring's Dependency Injection
Richard Paul
 
PDF
An introduction to React.js
Emanuele DelBono
 
PPTX
React JS - A quick introduction tutorial
Mohammed Fazuluddin
 
PDF
react-js-notes-for-professionals-book.pdf
AdilKhalki1
 
ODP
Dependency Injection in Spring in 10min
Corneil du Plessis
 
PDF
ReactJS
Hiten Pratap Singh
 
PPTX
React js programming concept
Tariqul islam
 
PDF
Lets make a better react form
Yao Nien Chung
 
PPTX
Introduction to react_js
MicroPyramid .
 
PDF
Java Course 11: Design Patterns
Anton Keks
 
PPTX
Hibernate
Prashant Kalkar
 
PPTX
React workshop
Imran Sayed
 
PPTX
React.js - The Dawn of Virtual DOM
Jimit Shah
 
PPT
React js
Jai Santhosh
 
PDF
Jetpack Compose a new way to implement UI on Android
Nelson Glauber Leal
 
reactJS
Syam Santhosh
 
C# コーディングガイドライン 2013/02/26
Yoshihisa Ozaki
 
Introduction to React JS for beginners
Varun Raj
 
React render props
Saikat Samanta
 
Introduction to Spring's Dependency Injection
Richard Paul
 
An introduction to React.js
Emanuele DelBono
 
React JS - A quick introduction tutorial
Mohammed Fazuluddin
 
react-js-notes-for-professionals-book.pdf
AdilKhalki1
 
Dependency Injection in Spring in 10min
Corneil du Plessis
 
React js programming concept
Tariqul islam
 
Lets make a better react form
Yao Nien Chung
 
Introduction to react_js
MicroPyramid .
 
Java Course 11: Design Patterns
Anton Keks
 
Hibernate
Prashant Kalkar
 
React workshop
Imran Sayed
 
React.js - The Dawn of Virtual DOM
Jimit Shah
 
React js
Jai Santhosh
 
Jetpack Compose a new way to implement UI on Android
Nelson Glauber Leal
 

Similar to Higher Order Components and Render Props (20)

PDF
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
JSFestUA
 
PPTX
React 16: new features and beyond
Artjoker
 
PDF
Road to react hooks
Younes (omar) Meliani
 
PDF
React Back to the Future
500Tech
 
PDF
React new features and intro to Hooks
Soluto
 
PDF
Why react matters
ShihChi Huang
 
PDF
Higher-Order Components — Ilya Gelman
500Tech
 
PDF
2018 05-16 Evolving Technologies: React, Babel & Webpack
Codifly
 
PPTX
React & Redux for noobs
[T]echdencias
 
PPTX
React hooks
Ramy ElBasyouni
 
PDF
Enhance react app with patterns - part 1: higher order component
Yao Nien Chung
 
PPTX
ReactJS for Beginners
Oswald Campesato
 
PDF
How to practice functional programming in react
Netta Bondy
 
PDF
Getting Started with Relay Modern
Nikolas Burk
 
PDF
React.js: You deserve to know about it
Anderson Aguiar
 
PDF
TDC2016SP - Trilha Frameworks JavaScript
tdc-globalcode
 
PDF
React for Beginners
Derek Willian Stavis
 
PDF
Quick start with React | DreamLab Academy #2
DreamLab
 
PDF
Matteo Antony Mistretta - Refactoring into React hooks - Codemotion Rome 2019
Codemotion
 
PDF
React JS & Functional Programming Principles
Andrii Lundiak
 
JS Fest 2019. Glenn Reyes. With great power comes great React hooks!
JSFestUA
 
React 16: new features and beyond
Artjoker
 
Road to react hooks
Younes (omar) Meliani
 
React Back to the Future
500Tech
 
React new features and intro to Hooks
Soluto
 
Why react matters
ShihChi Huang
 
Higher-Order Components — Ilya Gelman
500Tech
 
2018 05-16 Evolving Technologies: React, Babel & Webpack
Codifly
 
React & Redux for noobs
[T]echdencias
 
React hooks
Ramy ElBasyouni
 
Enhance react app with patterns - part 1: higher order component
Yao Nien Chung
 
ReactJS for Beginners
Oswald Campesato
 
How to practice functional programming in react
Netta Bondy
 
Getting Started with Relay Modern
Nikolas Burk
 
React.js: You deserve to know about it
Anderson Aguiar
 
TDC2016SP - Trilha Frameworks JavaScript
tdc-globalcode
 
React for Beginners
Derek Willian Stavis
 
Quick start with React | DreamLab Academy #2
DreamLab
 
Matteo Antony Mistretta - Refactoring into React hooks - Codemotion Rome 2019
Codemotion
 
React JS & Functional Programming Principles
Andrii Lundiak
 
Ad

Recently uploaded (20)

PPTX
UI5Con 2025 - Beyond UI5 Controls with the Rise of Web Components
Wouter Lemaire
 
PDF
Rethinking Security Operations - Modern SOC.pdf
Haris Chughtai
 
PDF
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
PPTX
Lecture 5 - Agentic AI and model context protocol.pptx
Dr. LAM Yat-fai (林日辉)
 
PDF
Trading Volume Explained by CIFDAQ- Secret Of Market Trends
CIFDAQ
 
PPTX
python advanced data structure dictionary with examples python advanced data ...
sprasanna11
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PPTX
TYPES OF COMMUNICATION Presentation of ICT
JulieBinwag
 
PDF
Market Insight : ETH Dominance Returns
CIFDAQ
 
PDF
Shuen Mei Parth Sharma Boost Productivity, Innovation and Efficiency wit...
AWS Chicago
 
PDF
Julia Furst Morgado The Lazy Guide to Kubernetes with EKS Auto Mode + Karpenter
AWS Chicago
 
PDF
Novus-Safe Pro: Brochure-What is Novus Safe Pro?.pdf
Novus Hi-Tech
 
PPTX
The Yotta x CloudStack Advantage: Scalable, India-First Cloud
ShapeBlue
 
PDF
Women in Automation Presents: Reinventing Yourself — Bold Career Pivots That ...
DianaGray10
 
PPTX
Darren Mills The Migration Modernization Balancing Act: Navigating Risks and...
AWS Chicago
 
PDF
Lecture A - AI Workflows for Banking.pdf
Dr. LAM Yat-fai (林日辉)
 
PPTX
Machine Learning Benefits Across Industries
SynapseIndia
 
PDF
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
PDF
Arcee AI - building and working with small language models (06/25)
Julien SIMON
 
PPTX
Simplifying End-to-End Apache CloudStack Deployment with a Web-Based Automati...
ShapeBlue
 
UI5Con 2025 - Beyond UI5 Controls with the Rise of Web Components
Wouter Lemaire
 
Rethinking Security Operations - Modern SOC.pdf
Haris Chughtai
 
Empowering Cloud Providers with Apache CloudStack and Stackbill
ShapeBlue
 
Lecture 5 - Agentic AI and model context protocol.pptx
Dr. LAM Yat-fai (林日辉)
 
Trading Volume Explained by CIFDAQ- Secret Of Market Trends
CIFDAQ
 
python advanced data structure dictionary with examples python advanced data ...
sprasanna11
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
TYPES OF COMMUNICATION Presentation of ICT
JulieBinwag
 
Market Insight : ETH Dominance Returns
CIFDAQ
 
Shuen Mei Parth Sharma Boost Productivity, Innovation and Efficiency wit...
AWS Chicago
 
Julia Furst Morgado The Lazy Guide to Kubernetes with EKS Auto Mode + Karpenter
AWS Chicago
 
Novus-Safe Pro: Brochure-What is Novus Safe Pro?.pdf
Novus Hi-Tech
 
The Yotta x CloudStack Advantage: Scalable, India-First Cloud
ShapeBlue
 
Women in Automation Presents: Reinventing Yourself — Bold Career Pivots That ...
DianaGray10
 
Darren Mills The Migration Modernization Balancing Act: Navigating Risks and...
AWS Chicago
 
Lecture A - AI Workflows for Banking.pdf
Dr. LAM Yat-fai (林日辉)
 
Machine Learning Benefits Across Industries
SynapseIndia
 
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
Arcee AI - building and working with small language models (06/25)
Julien SIMON
 
Simplifying End-to-End Apache CloudStack Deployment with a Web-Based Automati...
ShapeBlue
 
Ad

Higher Order Components and Render Props

  • 5. Higher Order Functions A function which takes one or more arguments and returns a functions
  • 7. function multiply(firstNumber) { return function(secondNumber) { return firstNumber * secondNumber } } multiply(3)(4)
  • 8. throttle = (callback: Function, wait: number) => { };
  • 9. throttle = (callback: Function, wait: number) => { let time = Date.now(); return function() { }; };
  • 10. throttle = (callback: Function, wait: number) => { let time = Date.now(); return function() { if (time + wait - Date.now() < 0) { callback.apply(this, arguments); time = Date.now(); } }; };
  • 11. throttle = (callback: Function, wait: number) => { let time = Date.now(); return function() { if (time + wait - Date.now() < 0) { callback.apply(this, arguments); time = Date.now(); } }; }; <Input onChange={this.throttle(this.handleInputChange, 500)} />
  • 12. Higher Order Functions A function which takes one or more arguments and returns a functions
  • 13. Higher Order Functions A function which takes one or more arguments and returns a functions Component
  • 14. Higher Order Functions A function which takes one or more arguments and returns a functions Component A function which takes a component as an argument and returns a new component
  • 16. function myHigherOrderComponent(Component) { return class extends React.Component { } }
  • 17. function myHigherOrderComponent(Component) { return class extends React.Component { render() { return <Component /> } } }
  • 18. function myHigherOrderComponent(Component) { return class extends React.Component { render() { return <Component {...this.props}/> } } }
  • 19. function myHigherOrderComponent(Component) { return class extends React.Component { render() { return <Component {...this.props}/> } } } export default myHigherOrderComponent(App);
 <EnhancedApp foo={bar}/>
  • 20. Alternative to Mixins Pattern Encapsulates Logic that can be shared easily Access data from any part of the component life cycle
  • 21. Some real world use cases please
  • 23. function asyncComponent(importComponent: Function, LoadingComponent: Function) { class AsyncComponent extends Component { } return AsyncComponent; }
  • 24. function asyncComponent(importComponent: Function, LoadingComponent: Function) { class AsyncComponent extends Component { constructor(props) { super(props); this.state = { component: null }; } } return AsyncComponent; }
  • 25. function asyncComponent(importComponent: Function, LoadingComponent: Function) { class AsyncComponent extends Component { constructor(props) { super(props); this.state = { component: null }; } render() { const C = this.state.component; return C ? <C {...this.props} /> : <LoadingComponent />; } } return AsyncComponent; }
  • 26. function asyncComponent(importComponent: Function, LoadingComponent: Function) { class AsyncComponent extends Component { constructor(props) { super(props); this.state = { component: null }; } async componentDidMount() { const { default: component } = await importComponent(); this.setState({ component: component }); } render() { const C = this.state.component; return C ? <C {...this.props} /> : <LoadingComponent />; } } return AsyncComponent; }
  • 27. class App extends Component { render() { <div> <Switch> </Switch> </div> } }
  • 28. const Products = asyncComponent(() => import('./pages/Products'), LoaderComponent); const HomePage = asyncComponent(() => import('./pages/HomePage'), LoaderComponent); class App extends Component { render() { <div> <Switch> <Route exact path={'/'} component={HomePage} /> <Route exact path={'/products'} component={Products} /> </Switch> </div> } }
  • 30. const wrapComponentWithData = (WrappedComponent) => { return class CustomComponent extends React.Component { render() { return <WrappedComponent {...this.props} />; } }; };
  • 31. const wrapComponentWithData = (WrappedComponent, InitialData) => { return class CustomComponent extends React.Component { render() { return <WrappedComponent {...InitialData} {...this.props} />; } }; };
  • 32. const wrapComponentWithData = (WrappedComponent, InitialData) => { return class CustomComponent extends React.Component { render() { return <WrappedComponent {...InitialData} {...this.props} />; } }; }; class App extends Component { render() { const data = { this.props } return ( <div> <Switch> <Route exact path={'/'} component={wrapComponentWithData(Homepage, data)} /> <Route exact path={'/products'} component={wrapComponentWithData(Products, data)} /> </Switch> </div> ); } }
  • 34. import TrackerLib from 'tracker.js' const withTracking = (Component, pageName, eventObject) => { };
  • 35. import TrackerLib from 'tracker.js' const withTracking = (Component, pageName, eventObject) => { return class CustomComponent extends React.Component { render() { return <Component {...this.props} />; } }; };
  • 36. import TrackerLib from 'tracker.js' const withTracking = (Component, pageName, eventObject) => { return class CustomComponent extends React.Component { componentDidMount() { TrackerLib.event(pageName, ...eventObject) } render() { return <Component {...this.props} />; } }; };
  • 37. import TrackerLib from 'tracker.js' const withTracking = (Component, pageName, eventObject) => { return class CustomComponent extends React.Component { componentDidMount() { TrackerLib.event(pageName, ...eventObject) } render() { return <Component {...this.props} />; } }; }; export default withTracking(HomePage, 'Home Page', {});
  • 39. function componentLogger(WrappedComponent) { return class extends React.Component { render() { return <WrappedComponent {...this.props} />; } } }
  • 40. function componentLogger(WrappedComponent) { return class extends React.Component { componentWillReceiveProps(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); } render() { return <WrappedComponent {...this.props} />; } } }
  • 41. function componentLogger(WrappedComponent) { return class extends React.Component { componentWillReceiveProps(nextProps) { console.log('Current props: ', this.props); console.log('Next props: ', nextProps); } render() { return <WrappedComponent {...this.props} />; } } } export default componentLogger(HomePage);
  • 44. Some Handy Tips Avoid using HOCs inside the render method
  • 45. Avoid using HOCs inside the render method Some Handy Tips render() { const EnhancedComponent = enhance(MyComponent); return <EnhancedComponent />; }
  • 46. Some Handy Tips render() { const EnhancedComponent = enhance(MyComponent); return <EnhancedComponent />; } Avoid using HOCs inside the render method
  • 47. Refs Aren’t Passed Through Some Handy Tips
  • 48. Refs Aren’t Passed Through Some Handy Tips function Field({ inputRef, ...rest }) { return <input ref={inputRef} {...rest} />; }
  • 49. Refs Aren’t Passed Through Some Handy Tips function Field({ inputRef, ...rest }) { return <input ref={inputRef} {...rest} />; } const EnhancedField = enhance(Field); <EnhancedField inputRef={(inputEl) => { this.inputEl = inputEl }} />
  • 50. Refs Aren’t Passed Through Some Handy Tips function Field({ inputRef, ...rest }) { return <input ref={inputRef} {...rest} />; } const EnhancedField = enhance(Field); <EnhancedField inputRef={(inputEl) => { this.inputEl = inputEl }} /> // Inside Your HOC this.inputEl.focus();
  • 51. Common examples of HOC connect of Redux createContainer of Relay Downshift UrQl
  • 56. Props A prop is an object for passing data to a component
  • 57. Render Prop A render prop is a function prop that a component uses to know what to render
  • 58. class Posts extends React.Component { state = { posts: getInitialPostData() } render() { return ( <div> {this.state.posts.map(post => <Post post={post} key={post.id}/>)} </div> ) } }
  • 59. class Posts extends React.Component { state = { posts: getInitialPostData() } render() { return ( <div> {this.state.posts.map(post => <Post post={post} key={post.id}/>)} </div> ) } } <Posts />
  • 60. class Posts extends React.Component { state = { posts: getInitialPostData() } render() { return ( <div> {this.state.posts.map(post => <Post post={post} key={post.id}/>)} </div> ) } }
  • 61. class Posts extends React.Component { state = { posts: getInitialPostData() } render() { return ( <div> {this.props.render(this.state)} </div> ) } }
  • 62. class Posts extends React.Component { state = { posts: getInitialPostData() } render() { return ( <div> {this.props.render(this.state)} </div> ) } } <Posts render={({ posts }) => posts.map(post => <Post post={post} />)} />
  • 63. Can i use children ??? 🤔
  • 64. class Posts extends React.Component { state = { posts: getInitialPostData() } render() { return ( <div> {this.props.children(this.state)} </div> ) } }
  • 65. class Posts extends React.Component { state = { posts: getInitialPostData() } render() { return ( <div> {this.props.children(this.state)} </div> ) } } <Posts> { ({ posts }) => posts.map(post => <Post post={post} />) } </Posts>
  • 66. Fully declarative approach using props No props naming collision Eases reusability of components
  • 67. Where can i use a Render prop?
  • 69. class List extends React.Component { state = { list: [], isLoading: false, }; componentDidMount() { this.setState({ isLoading: true }, this.fetchData); } fetchData = async () => { const res = await fetch(this.props.url); const json = await res.json(); this.setState({ list: json, isLoading: false, }); } }
  • 70. class List extends React.Component { state = { list: [], isLoading: false, }; componentDidMount() { this.setState({ isLoading: true }, this.fetchData); } fetchData = async () => { const res = await fetch(this.props.url); const json = await res.json(); this.setState({ list: json, isLoading: false, }); } render() { return this.props.render(this.state); } }
  • 72. <List url="https://api.github.com/users/nitish24p/repos" render={({ list, isLoading }) => ( <div> <h2>My repos</h2> {isLoading && <h2>Loading...</h2>} <ul> {list.length > 0 && list.map(repo => ( <li key={repo.id}> {repo.full_name} </li> ))} </ul> </div> )} />
  • 74. class Location extends Component { }
  • 75. class Location extends Component { state = { latitude: undefined, longititude: undefined } fetchGeoLocation = async () => { const res = await fetch("api/url"); const json = await res.json(); this.setState({ latitude: json.lat, longitude: json.long, }); } }
  • 76. class Location extends Component { state = { latitude: undefined, longititude: undefined } fetchGeoLocation = async () => { const res = await fetch("api/url"); const json = await res.json(); this.setState({ latitude: json.lat, longitude: json.long, }); } render() { const { latitude, longitude } = this.state; return this.props.children({ latitude, longitude, fetchLocation: this.fetchGeoLocation }); } }
  • 78. <Location> {({ latitude, longitude, fetchLocation }) => { }} </Location>
  • 79. <Location> {({ latitude, longitude, fetchLocation }) => { if (latitude && longitude) { return <Map marker={latitude, longitude}/> } return <Button label='Get Location' onClick={fetchLocation}/> }} </Location>
  • 82. Be careful when using Render Props with React.PureComponent Handy Tip
  • 83. Be careful when using Render Props with React.PureComponent Use function reference instead of arrow fn Handy Tip this.renderPosts = ({ posts }) => { return posts.map(post => <Post post={post} /> } <Posts render={this.renderPosts} />
  • 84. Common examples of render props withRouter of React Router Motion of React Motion Downshift UrQl
  • 85. Can i create a HOC using a Render Prop
  • 86. Can i create a HOC using a Render Prop
  • 87. Can i create a HOC using a Render Prop const withRouter = (Component) => { const C = (props) => { const { wrappedComponentRef, ...remainingProps } = props return ( <Route render={routeComponentProps => ( <Component {...remainingProps} {...routeComponentProps} ref={wrappedComponentRef} /> )} /> ) } ... }
  • 88. function HigherOrderCompCounter(Component) { return class extends React.Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render () { return <Component counter={this.state.counter} {...this.props}/> } } } const HOCCounter = HigherOrderCompCounter(CounterComponent); <HOCCounter /> class Counter extends Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render() { return this.props.children(this.state); } } <Counter> {({ counter }) => <h1>{counter}</h1>} </Counter> Higher order Component Render Prop const CounterComponent = ({ counter }) => <h1>{counter}</h1>
  • 89. function HigherOrderCompCounter(Component) { return class extends React.Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render () { return <Component counter={this.state.counter} {...this.props}/> } } } const HOCCounter = HigherOrderCompCounter(CounterComponent); <HOCCounter /> class Counter extends Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render() { return this.props.children(this.state); } } <Counter> {({ counter }) => <h1>{counter}</h1>} </Counter> Higher order Component Render Prop const CounterComponent = ({ counter }) => <h1>{counter}</h1>
  • 90. function HigherOrderCompCounter(Component) { return class extends React.Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render () { return <Component counter={this.state.counter} {...this.props}/> } } } const HOCCounter = HigherOrderCompCounter(CounterComponent); <HOCCounter /> class Counter extends Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render() { return this.props.children(this.state); } } <Counter> {({ counter }) => <h1>{counter}</h1>} </Counter> Higher order Component Render Prop const CounterComponent = ({ counter }) => <h1>{counter}</h1>
  • 91. function HigherOrderCompCounter(Component) { return class extends React.Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render () { return <Component counter={this.state.counter} {...this.props}/> } } } const HOCCounter = HigherOrderCompCounter(CounterComponent); <HOCCounter /> class Counter extends Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render() { return this.props.children(this.state); } } <Counter> {({ counter }) => <h1>{counter}</h1>} </Counter> Higher order Component Render Prop const CounterComponent = ({ counter }) => <h1>{counter}</h1>
  • 92. function HigherOrderCompCounter(Component) { return class extends React.Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render () { return <Component counter={this.state.counter} {...this.props}/> } } } const HOCCounter = HigherOrderCompCounter(CounterComponent); <HOCCounter /> class Counter extends Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render() { return this.props.children(this.state); } } <Counter> {({ counter }) => <h1>{counter}</h1>} </Counter> Higher order Component Render Prop const CounterComponent = ({ counter }) => <h1>{counter}</h1>
  • 93. function HigherOrderCompCounter(Component) { return class extends React.Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render () { return <Component counter={this.state.counter} {...this.props}/> } } } const HOCCounter = HigherOrderCompCounter(CounterComponent); <HOCCounter /> class Counter extends Component { state = { counter: 0 } componentDidMount() { setInterval(() => { this.setState((prevState) => ({counter: prevState.counter + 1})); }, 1000) } render() { return this.props.children(this.state); } } <Counter> {({ counter }) => <h1>{counter}</h1>} </Counter> Higher order Component Render Prop const CounterComponent = ({ counter }) => <h1>{counter}</h1>