Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save granmoe/e344fe1f89ff171d94cfb71674090477 to your computer and use it in GitHub Desktop.
Save granmoe/e344fe1f89ff171d94cfb71674090477 to your computer and use it in GitHub Desktop.
Simple form validation through a Higher Order Component. Same as the other ones I made, except this caches functions so shouldComponentUpdate of the child doesn't always return true.
import React from 'react'
export default options => {
return WrappedComponent => class FormValidation extends React.Component {
constructor () {
super()
this.validate = options.validate
this.cachedFunctions = { onChange: {}, onBlur: {} }
this.state = options.fields.reduce((result, field) => {
result.fields.push(field)
result.errors[field] = ''
result.values[field] = ''
result.touched[field] = false
return result
}, { fields: [], errors: {}, values: {}, touched: {} })
}
onBlur (field, e) {
const touched = this.state.touched
touched[field] = true
this.setState({ touched })
this.runValidate(field, e.target.value)
}
onChange (field, e) {
this.runValidate(field, e.target.value)
}
runValidate = (field, value) => {
const values = this.state.values
values[field] = value
this.setState(this.validate(values)) // TODO: Only need to validate the value that changed here
}
getCachedFunction (functionName, fieldName) {
if (!this.cachedFunctions[functionName][fieldName]) {
this.cachedFunctions[functionName][fieldName] = this[functionName]['bind'](this, fieldName)
}
return this.cachedFunctions[functionName][fieldName]
}
mapStateToChildProps = (state) => {
return state.fields.reduce((result, field) => {
result[field] = {
value: state.values[field],
error: state.errors[field],
touched: state.touched[field],
onChange: this.getCachedFunction('onChange', field),
onBlur: this.getCachedFunction('onBlur', field),
}
return result
}, {})
}
render () {
return <WrappedComponent {...this.props} {...this.mapStateChildToProps(this.state)} isValid={this.isValid(this.state)} />
}
isValid (state) {
return state.fields.reduce((previous, current) => previous && (!!state.values[current] && !state.errors[current]), true)
}
}
}
@TimothyJohnK
Copy link

I'd love to get walked through this in person sometime. Maybe after I have two days of React under my belt I'll understand it.

@granmoe
Copy link
Author

granmoe commented May 9, 2017

@TimothyJohnK Anytime, just remind me next time we hang out :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment