Share
Embed
Advanced Component Patterns
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.
Siddharth Kshetrapal
January 19, 2018
Transcript
134 slides
-
const TextInput = props => { return ( <input className="input"
type="text" placeholder={props.placeholder} /> ) } render( <TextInput placeholder="Enter some text" /> ) -
const TextInput = props => { return ( <input className="input"
type="text" placeholder={props.placeholder} /> ) } render( <TextInput placeholder="Enter some text" /> ) -
const TextInput = props => { return ( <input className="input"
type="text" placeholder={props.placeholder} /> ) } render( <TextInput readOnly placeholder="Enter some text" /> ) -
const TextInput = props => { let classes = 'input'
if (props.readOnly) classes += ' readonly' return ( <input className={classes} type="text" placeholder={props.placeholder} /> ) } render( <TextInput readOnly placeholder="Enter some text" /> ) -
const TextInput = props => { let classes = '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" /> ) -
const TextInput = props => { let classes = '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" /> ) -
const TextInput = props => { return ( <input className="input"
type="text" placeholder={props.placeholder} /> ) } 0 chars -
const TextInput = 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) { super(props) this.state =
{ 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) { super(props) this.state =
{ 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 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) { ... } 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) { ... } onChange
= (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) { super(props) this.state =
{ length: 0 } } onChange = (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 { state = { length: 0
} onChange = (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 { state = { length: 0
} onChange = (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 { state = { length: 0
} onChange = (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 { render() { return ( <input
type="text" placeholder={this.props.placeholder} /> ) } } email -
class TextInput extends React.Component { render() { return ( <input
type="text" placeholder={this.props.placeholder} /> ) } } email SIDDHARTH -
class TextInput extends React.Component { state = { value: ''
} render() { return ( <input value={this.state.value} type="text" placeholder={this.props.placeholder} /> ) } } email -
class TextInput extends React.Component { state = { value: ''
} render() { return ( <input value={this.state.value} type="text" placeholder={this.props.placeholder} /> ) } } email s -
class TextInput extends React.Component { state = { value: ''
} render() { return ( <input value={this.state.value} type="text" placeholder={this.props.placeholder} /> ) } } email s -
class TextInput extends React.Component { state = { value: ''
} onChange = (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 -
class TextInput extends React.Component { state = { value: ''
} onChange = (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 [email protected] [email protected] -
const withLabel = (label, Component) => { } render( withLabel(‘address',
<TextArea placeholder="Enter some text" />) ) address -
const withLabel = (label, Component) => { return ( <div
className="form-field"> <label>{label}</label> <Component/> </div> ) } render( withLabel(‘address', <TextArea placeholder="Enter some text" />) ) address -
const withLabel = (label, Component) => { return ( <div
className="form-field"> <label>{label}</label> <Component/> </div> ) } render( withLabel(‘address', <TextArea placeholder="Enter some text" />) ) address -
const withLabel = (label, Component) => { return ( <div
className="form-field"> <label>{label}</label> <Component/> </div> ) } render( <WithLabel label="address"> <TextArea placeholder="Enter some text" /> </WithLabel> ) address -
const WithLabel = (props) => { return ( <div className="form-field">
<label>{label}</label> <Component/> </div> ) } render( <WithLabel label="address"> <TextArea placeholder="Enter some text" /> </WithLabel> ) address -
const withLabel = (props) => { return ( <div className="form-field">
<label>{label}</label> {props.children} </div> ) } render( <WithLabel label="address"> <TextArea placeholder="Enter some text" /> </WithLabel> ) address -
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> ) email -
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> ) 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> ) email -
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 -
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 -
const Form = (props) => { return (<form>{ props.children }</form>)
} <Form.TextInput label="email" placeholder="Enter some text" /> <Form.TextArea label="address" placeholder="Enter some text" /> email -
const Form = (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" /> email -
const Form = (props) => { return (<form>{ props.children }</form>)
} Form.TextInput = props => { return ( <WithLabel label={props.label}> <TextInput placeholder={props.placeholder} /> </WithLabel> ) } Form.TextArea = props => { return ( <WithLabel label={props.label}> <TextArea placeholder={props.placeholder} /> </WithLabel> email -
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 -
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 -
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) { const error = 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) { const error = 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 } />) -
0 chars PROJECT NAME Abc really long name, omg goes
on and on 34 chars class TextInput extends React.Component { ... } render(<TextInput renderLabel={ renderLabel } />) const renderLabel = (length) => { return <span> {length} chars </span> } -
0 chars PROJECT NAME Abc really long name, omg goes
on and on 34 chars class TextInput extends React.Component { ... } render(<TextInput renderLabel={ renderLabel } />) const renderLabel = (length) => { return <span> {length} chars </span> } -
0 chars PROJECT NAME Abc really long name, omg goes
on and on 34 chars class TextInput extends React.Component { ... } render(<TextInput renderLabel={ renderLabel } />) const renderLabel = (length) => { let className if (length > 25) className = 'warn' else if (length > 30) className = '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( <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 } } ThemeProvider.childContextTypes = { theme: PropTypes.string } -
render( <ThemeProvider name="extend"> <App /> </ThemeProvider> ) class ThemeProvider extends
React.Component { ... } ThemeProvider.childContextTypes = { theme: PropTypes.string } -
render( <ThemeProvider name="extend"> <App /> </ThemeProvider> ) class ThemeProvider extends
React.Component { ... } ThemeProvider.childContextTypes = { theme: PropTypes.string } const Button = (props) => { return <button className="button">{props.children}</button> } -
render( <ThemeProvider name="extend"> <App /> </ThemeProvider> ) class ThemeProvider extends
React.Component { ... } ThemeProvider.childContextTypes = { theme: PropTypes.string } const Button = (props) => { return <button className="button">{props.children}</button> } Button.contextTypes = { theme: PropTypes.string } -
render( <ThemeProvider name="extend"> <App /> </ThemeProvider> ) class ThemeProvider extends
React.Component { ... } ThemeProvider.childContextTypes = { theme: PropTypes.string } const Button = (props, context) => { return <button className="button">{props.children}</button> } Button.contextTypes = { theme: PropTypes.string } -
render( <ThemeProvider name="extend"> <App /> </ThemeProvider> ) class ThemeProvider extends
React.Component { ... } ThemeProvider.childContextTypes = { theme: PropTypes.string } const Button = (props, context) => { let className = 'button' + 'button-' + context.theme return <button className={className}>{props.children}</button> } Button.contextTypes = { theme: PropTypes.string } -
class ThemeProvider extends React.Component { ... } ThemeProvider.childContextTypes = {
theme: PropTypes.string } const Button = (props, context) => { let className = 'button' + 'button-' + context.theme return <button className={className}>{props.children}</button> } Button.contextTypes = { theme: PropTypes.string } render( <ThemeProvider name="extend"> <App /> </ThemeProvider> ) -
class ThemeProvider extends React.Component { ... } ThemeProvider.childContextTypes = {
theme: PropTypes.string } const Button = (props, context) => { let className = 'button' + 'button-' + context.theme return <button className={className}>{props.children}</button> } addContext(Button) render( <ThemeProvider name="extend"> <App /> </ThemeProvider> ) -
class ThemeProvider extends React.Component { ... } ThemeProvider.childContextTypes = {
theme: PropTypes.string } export function addContext (Component) { Component['contextTypes'] = { theme: PropTypes.string } return Component } ----- const Button = (props, context) => { let className = 'button' + 'button-' + context.theme return <button className={className}>{props.children}</button> } addContext(Button)