Advanced
Component
Patterns
A presentation at ReactFoo Pune in January 2018 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