A presentation at ReactFoo Pune in in Pune, Maharashtra, India by Siddharth Kshetrapal
Advanced
Component
Patterns
siddharthkp
I teach React
MUST LEARN ALL PATTERNS
7 component patterns
DESIGN DEVELOPMENT
props =>
{ return
( < input className =" input " type =" text " placeholder ={ props . placeholder } /> ) } render ( < TextInput placeholder =" Enter
some
text"
/> )
props =>
{ return
( < input className =" input " type =" text " placeholder ={ props . placeholder } /> ) } render ( < TextInput placeholder =" Enter
some
text"
/> )
props =>
{ return
( < input className =" input " type =" text " placeholder ={ props . placeholder } /> ) } render ( < TextInput readOnly placeholder =" Enter
some
text"
/> )
props =>
'input' if
( props . readOnly ) classes +=
' readonly' return
( < input className ={ classes } type =" text " placeholder ={ props . placeholder } /> ) } render ( < TextInput readOnly placeholder =" Enter
some
text"
/> )
props =>
'input' if
( props . readOnly ) classes +=
' readonly' return
( < input className ={ classes } type =" text " placeholder ={ props . placeholder } readOnly ={ props . readOnly } /> ) } render ( < TextInput readOnly placeholder =" Enter
some
text"
/> )
Functional component
props =>
'input' if
( props . readOnly ) classes +=
' readonly' return
( < input className ={ classes } type =" text " placeholder ={ props . placeholder } readOnly ={ props . readOnly } /> ) } render ( < TextInput readOnly placeholder =" Enter
some
text"
/> )
0 chars
props =>
{ return
( < input className =" input " type =" text " placeholder ={ props . placeholder } /> ) } 0 chars
props =>
{ return
( < div
< span
0 chars </ span
< input className =" input " type =" text " placeholder ={ props . placeholder } /> </ div
) } 0 chars
class TextInput extends React . Component { render ()
{ return
( < div
< span
0 chars </ span
< input className =" input " type =" text " placeholder ={ props . placeholder } /> </ div
) } } 0 chars
class TextInput extends React . Component { render ()
{ return
( < div
< span
0 chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder } /> </ div
) } } 0 chars
class TextInput extends React . Component { constructor (props)
{ length :
0
} } render ()
{ return
( < div
< span
0 chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder } /> </ div
) } } 0 chars
class TextInput extends React . Component { constructor (props)
{ length :
0
} } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder } /> </ div
) } } 0 chars
class TextInput extends React . Component { constructor (props)
{ ... } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder } /> </ div
) } } 0 chars
class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ this . setState ({ length : event . target . value . length }) } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder } /> </ div
) } } 0 chars
class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ this . setState ({ length : event . target . value . length }) } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange . bind ( this )} /> </ div
) } 0 chars Abc 3 chars
Class component
class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ this . setState ({ length : event . target . value . length }) } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange . bind ( this )} /> </ div
) } 0 chars Abc 3 chars
class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ this . setState ({ length : event . target . value . length }) } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange . bind ( this )} /> </ div
) } 0 chars Abc 3 chars
class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ this . setState ({ length : event . target . value . length }) } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange } /> </ div
) } 0 chars Abc 3 chars
class TextInput extends React . Component { constructor (props)
( event )
=> { this . setState ({ length : event . target . value . length }) } render ()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange } /> </ div
) } 0 chars Abc 3 chars
class TextInput extends React . Component { constructor (props)
( event )
=>
{ ... }
render
()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange } /> </ div
) 0 chars Abc 3 chars
class TextInput extends React . Component { constructor (props)
{ length :
0
( event )
=>
{ ... }
render
()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange } /> </ div
) 0 chars Abc 3 chars
{ length :
0
( event )
=>
{ ... }
render
()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange } /> </ div
) 0 chars Abc 3 chars
{ length :
0
( event )
=>
{ ... }
render
()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange } /> </ div
) } } 0 chars Abc 3 chars
1/3
{ length :
0
( event )
=>
{ ... }
render
()
{ return
( < div
< span
{ this . state . length } chars </ span
< input className =" input " type =" text " placeholder ={ this . props . placeholder
onChange ={ this . onChange } /> </ div
) } } 0 chars Abc 3 chars
0 chars email Siddharth@Gmail.Com siddharth@gmail.com
class TextInput extends React . Component { render ()
{ return
( < input type =" text " placeholder ={ this . props . placeholder } /> ) } } email
Un controlled component
class TextInput extends React . Component { render ()
{ return
( < input type =" text " placeholder ={ this . props . placeholder } /> ) } } email SIDDHARTH
{ value :
''
} render ()
{ return
( < input value ={ this . state . value } type =" text " placeholder ={ this . props . placeholder } /> ) } } email
{ value :
''
} render ()
{ return
( < input value ={ this . state . value } type =" text " placeholder ={ this . props . placeholder } /> ) } } email s
{ value :
''
} render ()
{ return
( < input value ={ this . state . value } type =" text " placeholder ={ this . props . placeholder } /> ) } } email s
{ value :
''
( event )
=> {
this . setState ({ value : event . target . value . toLowerCase ()
}) } render ()
{ return
( < input onChange ={ this . onChange } value ={ this . state . value } type =" text " placeholder ={ this . props . placeholder } /> ) } } email
{ value :
''
( event )
=> {
this . setState ({ value : event . target . value . toLowerCase ()
}) } render ()
{ return
( < input onChange ={ this . onChange } value ={ this . state . value } type =" text " placeholder ={ this . props . placeholder } /> ) } } email siddharth@gmail.com SIDDHARTH@Gmail.com
0 chars email siddharth@gmail.com address
render ( < TextArea placeholder =" Enter
some
text"
/> ) address
render ( withLabel ( ‘address' , < TextArea placeholder =" Enter
some
text"
/>) ) address
( label , Component )
=>
{ } render ( withLabel ( ‘address' , < TextArea placeholder =" Enter
some
text"
/>) ) address
( label , Component )
=>
{ return
( < div className =" form-field "> < label
{ label }</ label
< Component /> </ div
) } render ( withLabel ( ‘address' , < TextArea placeholder =" Enter
some
text"
/>) ) address
Higher Order Component
( label , Component )
=>
{ return
( < div className =" form-field "> < label
{ label }</ label
< Component /> </ div
) } render ( withLabel ( ‘address' , < TextArea placeholder =" Enter
some
text"
/>) ) address
( label , Component )
=>
{ return
( < div className =" form-field "> < label
{ label }</ label
< Component /> </ div
) } render ( < WithLabel label =" address "> < TextArea placeholder =" Enter
some
text"
/> </ WithLabel
) address
( props )
=>
{ return
( < div className =" form-field "> < label
{ label }</ label
< Component /> </ div
) } render ( < WithLabel label =" address "> < TextArea placeholder =" Enter
some
text"
/> </ WithLabel
) address
( props )
=>
{ return
( < div className =" form-field "> < label
{ label }</ label
{ props.children } </ div
) } render ( < WithLabel label =" address "> < TextArea placeholder =" Enter
some
text"
/> </ WithLabel
) address
address accept? email
render ( < form
</ form
render ( < form
< WithLabel label =" address "> < TextInput placeholder =" Enter
some
text"
/> </ WithLabel
</ form
render ( < form
< WithLabel label =" address "> < TextInput placeholder =" Enter
some
text"
/> </ WithLabel
< WithLabel label =" address "> < TextArea
placeholder =" Enter
some
text"
/> </ WithLabel
< WithLabel label =" accept? "> < Switch
/> </ WithLabel
</ form
render ( < form
< WithLabel label =" address "> < TextInput placeholder =" Enter
some
text"
/> </ WithLabel
< WithLabel label =" address "> < TextArea
placeholder =" Enter
some
text"
/> </ WithLabel
< WithLabel label =" accept? "> < Switch
/> </ WithLabel
< div className =" actions "> < Button
primary
onClick ={ this . save }>Save</ Button
< Button
onClick ={ this . clear }>Clear</ Button
</ div
</ form
address accept? email
render ( < form
< WithLabel label =" address "> < TextInput placeholder =" Enter
some
text"
/> </ WithLabel
< WithLabel label =" address "> < Form.TextArea placeholder =" Enter
some
text"
/> </ WithLabel
< WithLabel label =“ accept? "> < Form.Switch /> </ WithLabel
< div className =" actions "> < Button
primary
onClick ={ this . save }>Save</ Button
< Button
onClick ={ this . clear }>Clear</ Button
</ div
</ form
render ( < Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =" accept? " /> < Form. Actions primary ={{ label :
'Save Changes' , method : this.save }} secondary ={{ label :
'Save Changes' ,
method : this.save }} /> </ Form
Compound Component ❤
compo compo
render ( < Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =" accept? " /> < Form. Actions primary ={{ label :
'Save Changes' , method : this.save }} secondary ={{ label :
'Save Changes' ,
method : this.save }} /> </ Form
< Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
( props )
=>
{ return
(< form
{ props.children }</ form ) } < Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
( props )
=>
{ return
(< form
{ props.children }</ form ) } Form . TextInput = props =>
{ return
( < WithLabel
label ={ props.label }> < TextInput placeholder ={ props.placeholder }
/> </ WithLabel
) } < Form.TextArea label =" address "
placeholder =" Enter
some
text"
( props )
=>
{ return
(< form
{ props.children }</ form ) } Form . TextInput = props =>
{ return
( < WithLabel
label ={ props.label }> < TextInput placeholder ={ props.placeholder }
/> </ WithLabel
props =>
{ return
( < WithLabel
label ={ props.label }> < TextArea placeholder ={ props.placeholder }
/> </ WithLabel
render ( < Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =" accept? " /> < Form. Actions primary ={{ label :
'Save Changes' , method : this.save }} secondary ={{ label :
'Save Changes' ,
method : this.save }} /> </ Form
email address accept?
render ( < Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =" accept? " /> < Form. Actions primary ={{ label :
'Save Changes' , method : this.save }} secondary ={{ label :
'Save Changes' ,
method : this.save }} /> </ Form
email address accept?
email address accept?
0 chars
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ this . setState ({ length : event . target . value . length }) } render ()
{ return
( < div
< input onChange ={ this . onChange . bind ( this ) /> < span
{ this . state . length } chars </ span
</ div
) } }
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
event . target . value . length
30 this . setState ({ length : event . target . value . length, error }) } render ()
{ return
( < div
< input onChange ={ this . onChange . bind ( this ) /> < span className ={...}>{ this . state . length } chars </ span
</ div
) } }
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
event . target . value . length
this . props.limit this . setState ({ length : event . target . value . length, error }) } render ()
{ return
( < div
< input onChange ={ this . onChange . bind ( this ) /> < span className ={...}>{ this . state . length } chars </ span
</ div
) } }
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { ... } render (< TextInput limit ={ 30 }
/>)
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars 0 chars Abc really long name, omg goes on 28 chars 2/3
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { ... } render (< TextInput limit ={ 30 }
/>)
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { ... } render (< TextInput renderLabel ={ renderLabel } />)
( length )
=>
{
return
< span
{ length } chars </ span
}
Render prop
( length )
=>
{
return
< span
{ length } chars </ span
}
( length )
=>
{
let className
if
( length
'warn'
else
if
( length
'error'
return
< span className ={ className }>
{ length } chars </ span
}
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ ... } render ()
{ return
( < div
< input onChange ={ this . onChange . bind ( this ) /> < span
{ this . state . length } chars </ span
</ div
) } }
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ ... } render ()
{ return
( < div
< input onChange ={ this . onChange . bind ( this ) /> {
this . props . renderLabel ()
} </ div
) } }
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ ... } render ()
{ return
( < div
< input onChange ={ this . onChange . bind ( this ) /> {
this . props . renderLabel ( this . state . length )
} </ div
) } }
0 chars PROJECT NAME Abc really long name, omg goes on and on 34 chars class TextInput extends React . Component { constructor (props)
{ ... } onChange ( event )
{ ... } render ()
{ return
( this . props . render ( this . state . length ) ) } }
< Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =“ accept? " theme =" manage " /> < Button theme =" manage ">Save Changes</ Button
</ Form
< Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =“ accept? " theme =" extend " /> < Button theme =" manage ">Save Changes</ Button
</ Form
< Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =“ accept? " theme =" extend " /> < Button theme =" manage ">Save Changes</ Button
</ Form
< Form
< Form.TextInput label =" email "
placeholder =" Enter
some
text"
/> < Form.TextArea label =" address "
placeholder =" Enter
some
text"
/> < Form.Switch label =“ accept? " theme =" extend " /> < Button theme =" extend ">Save Changes</ Button
</ Form
render (
< App /> )
render (
< ThemeProvider name =" manage ">
< App />
</ ThemeProvider
)
render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider
)
Provider Component
https://avatars3.githubusercontent.com/u/17475736?s=400&v=4 ✅ ✅ ✅
render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider
)
render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider> )
render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider> ) class ThemeProvider extends React . Component {
render ()
{
return
this . props . children
} }
render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider> ) class ThemeProvider extends React . Component {
getChildContext ()
{
return
{ theme :
this . props . name }
}
render ()
{
return
this . props . children
} }
render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider> ) class ThemeProvider extends React . Component {
getChildContext ()
{
return
{ theme :
this . props . name }
}
render ()
{
return
this . props . children
{ theme : PropTypes . string }
render (
< ThemeProvider name =" extend ">
< App />
{ theme : PropTypes . string }
render (
< ThemeProvider name =" extend ">
< App />
( props )
=>
{
return
< button className ="button">{ props . children }</ button
}
render (
< ThemeProvider name =" extend ">
< App />
( props )
=>
{
return
< button className ="button">{ props . children }</ button
{ theme : PropTypes . string }
render (
< ThemeProvider name =" extend ">
< App />
( props, context )
=>
{
return
< button className ="button">{ props . children }</ button
{ theme : PropTypes . string }
render (
< ThemeProvider name =" extend ">
< App />
( props, context )
=>
{
'button'
'button-'
context . theme
return
< button className ={ className }>{ props . children }</ button
{ theme : PropTypes . string }
render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider> )
render (
< ThemeProvider name =" manage ">
< App />
</ ThemeProvider> )
( props, context )
=>
{
'button'
'button-'
context . theme
return
< button className ={ className }>{ props . children }</ button
{ theme : PropTypes . string } render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider> )
( props, context )
=>
{
'button'
'button-'
context . theme
return
< button className ={ className }>{ props . children }</ button
} addContext (Button) render (
< ThemeProvider name =" extend ">
< App />
</ ThemeProvider> )
{ theme : PropTypes . string } export function addContext ( Component )
{ Component [ 'contextTypes' ]
=
{ theme : PropTypes . string
}
( props, context )
=>
{
'button'
'button-'
context . theme
return
< button className ={ className }>{ props . children }</ button
} addContext (Button)
✅
7 component patterns
I hope you learned something today
siddharthkp
React on it’s own has a very small API surface. Most of the magic happens in user-land. It feels like every month, someone from the community finds an innovative way of writing components. This is the best part about React, the creative community.
I’m going to be honest, this stresses me out. I have a constant fear of missing out on the cleanest/prettiest/smartest way of writing React components.
So, I sat and learnt all of them, so that you don’t have to.