Skip to content

Instantly share code, notes, and snippets.

@mjackson
Created February 9, 2017 05:34
Show Gist options
  • Save mjackson/e1007219bf13fa173ea9a27afadae370 to your computer and use it in GitHub Desktop.
Save mjackson/e1007219bf13fa173ea9a27afadae370 to your computer and use it in GitHub Desktop.
/*eslint-disable no-alert */
////////////////////////////////////////////////////////////////////////////////
// Exercise:
//
// Using context, implement the <Form>, <SubmitButton>, and <TextInput>
// components such that:
//
// - Clicking the <SubmitButton> "submits" the form
// - Hitting "Enter" while in a <TextInput> submits the form
// - Don't use a <form> element, we're intentionally recreating the
// browser's built-in behavior
//
// Got extra time?
//
// - Send the values of all the <TextInput>s to the <Form onChange> handler
// without using DOM traversal APIs
// - Implement a <ResetButton> that resets the <TextInput>s in the form
//
////////////////////////////////////////////////////////////////////////////////
import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
class Form extends React.Component {
static childContextTypes = {
form: PropTypes.shape({
submit: PropTypes.func,
change: PropTypes.func,
reset: PropTypes.func,
onReset: PropTypes.func.isRequired
}).isRequired
}
getChildContext() {
return {
form: {
submit: this.props.onSubmit,
change: this.props.onChange,
onReset: (listener) => {
this.listeners.push(listener)
},
reset: () => {
this.listeners.forEach(listener => listener())
}
}
}
}
componentWillMount() {
this.listeners = []
}
render() {
return <div>{this.props.children}</div>
}
}
class SubmitButton extends React.Component {
static contextTypes = {
form: PropTypes.shape({
submit: PropTypes.func.isRequired
}).isRequired
}
render() {
return <button onClick={this.context.form.submit}>{this.props.children}</button>
}
}
class ResetButton extends React.Component {
static contextTypes = {
form: PropTypes.shape({
reset: PropTypes.func.isRequired
}).isRequired
}
render() {
return <button onClick={this.context.form.reset}>{this.props.children}</button>
}
}
class TextInput extends React.Component {
static contextTypes = {
form: PropTypes.shape({
submit: PropTypes.func,
change: PropTypes.func,
onReset: PropTypes.func.isRequired
}).isRequired
}
handleKeyDown = (event) => {
if (event.key === 'Enter' && this.context.form.submit)
this.context.form.submit()
}
handleChange = (event) => {
this.setState({ value: event.target.value })
if (this.context.form.change)
this.context.form.change(event)
}
static defaultProps = {
value: ''
}
state = {
value: this.props.defaultValue
}
handleReset = () => {
this.setState({ value: '' })
}
componentDidMount() {
this.context.form.onReset(this.handleReset)
}
render() {
return (
<input
type="text"
name={this.props.name}
value={this.state.value}
placeholder={this.props.placeholder}
onKeyDown={this.handleKeyDown}
onChange={this.handleChange}
/>
)
}
}
class App extends React.Component {
handleChange = (event) => {
console.log(event.target.value)
}
handleSubmit = () => {
alert('YOU WIN!')
}
render() {
return (
<div>
<h1>This isn't even my final <code>&lt;Form/&gt;</code>!</h1>
<Form onChange={this.handleChange} onSubmit={this.handleSubmit}>
<p>
<TextInput name="firstName" placeholder="First Name"/> {' '}
<TextInput name="lastName" placeholder="Last Name"/>
</p>
<p>
<SubmitButton>Submit</SubmitButton>
<ResetButton>Reset</ResetButton>
</p>
</Form>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment