I have a number of these components, but will show just two as an example. They're very similar, but the differences are enough to where splitting them out felt needed. What I really need is some help. Is this the right approach, or would I be better served somehow combining them to reduce duplicate code? I have similar components for toggles like radios and checkboxes, as well as textarea that handle both plain text and markdown fields, etc.
Other feedback would also be appreciated :)
Textfield wrapper.
'use strict'
import React, { Component } from 'react'
import { FieldText, FieldLabel, FieldDescription, FieldErrorMessage } from './'
import PropTypes from 'prop-types'
class FieldTextWrap extends Component {
static propTypes = {}
constructor(props) {
super(props)
this.state = {
value: '',
isValid: true
}
}
_handleChange = value => {
const { formatter } = this.props
const formattedValue = !!formatter ? formatter(value) : value
this.setState({ value: formattedValue })
}
componentDidMount() {
const {
required,
type,
value,
initialValue,
dispatch,
handleBlur,
isForm,
formId,
id
} = this.props
!!initialValue && this.setState({ value: initialValue })
!initialValue && !!value && this.setState({ value })
const fieldData = {
id,
value,
type,
required,
formId,
valid: true
}
return isForm && dispatch(handleBlur(null, dispatch, fieldData))
}
componentDidUpdate(prevProps, prevState) {
const { validationRule, required } = this.props
const { value } = this.state
const didUpdate = prevState.value !== value
// validate and update
const isValid = !!validationRule
? validationRule.func({
field: { required, value },
tests: validationRule.tests,
options: validationRule.options
})
: true
didUpdate && this.setState({ isValid })
}
componentWillUnmount() {
const { removeFormField, id, isForm } = this.props
isForm && removeFormField(id)
}
render() {
const {
className = '',
description,
fieldGroup = '',
formName,
formId,
hideDescription,
hideLabel,
id,
label,
required,
requireDefault,
type,
validationText: message = ''
} = this.props
const classes = `form-item ${formName}__${id} ${fieldGroup} ${type}-field ${className} ${type} text-type`
const value = this.state.value
const isValid = this.state.isValid
const fieldData = {
id,
value,
type,
required,
formId,
valid: isValid,
message
}
return (
<div className={classes}>
<FieldLabel
name={id}
label={label}
required={required}
requireDefault={requireDefault}
hidden={hideLabel}
/>
<div className={`${type}-field__wrapper`}>
{isValid ? (
<FieldDescription
name={id}
description={description}
hidden={hideDescription}
/>
) : (
<FieldErrorMessage name={id} message={message} />
)}
<FieldText
{...this.props}
value={value}
handleChange={this._handleChange}
fieldData={fieldData}
/>
{type === 'date' && <div className="date-field__icon" />}
</div>
</div>
)
}
}
export default FieldTextWrap
Select Wrapper
'use strict'
import React, { Component } from 'react'
import {
FieldSelect,
FieldLabel,
FieldDescription,
FieldErrorMessage
} from './'
import PropTypes from 'prop-types'
class FieldSelectWrap extends Component {
static propTypes = {}
constructor(props) {
super(props)
this.state = {
value: '',
isValid: true
}
}
_handleChange = value => this.setState({ value })
componentDidMount() {
const {
required,
type,
value,
initialValue,
dispatch,
handleBlur,
isForm,
formId,
id
} = this.props
!!initialValue && this.setState({ value: initialValue })
!initialValue && !!value && this.setState({ value })
const fieldData = {
id,
value,
type,
required,
formId,
valid: true
}
return isForm && dispatch(handleBlur(null, dispatch, fieldData))
}
componentDidUpdate(prevProps, prevState) {
const { validationRule, required } = this.props
const { value } = this.state
const didUpdate = prevState.value !== value
// validate and update
const isValid = !!validationRule
? validationRule.func({
field: { required, value },
tests: validationRule.tests,
options: validationRule.options
})
: true
didUpdate && this.setState({ isValid })
}
componentWillUnmount() {
const { removeFormField, id, isForm } = this.props
isForm && removeFormField(id)
}
render() {
const {
className = '',
description,
fieldGroup = '',
formName,
formId,
hideDescription,
hideLabel,
id,
label,
required,
requireDefault,
type,
validationText: message = ''
} = this.props
const classes = `form-item ${formName}__${id} ${fieldGroup} ${type}-field ${className} ${type}`
const value = this.state.value
const isValid = this.state.isValid
const fieldData = {
id,
value,
type,
required,
formId,
valid: isValid,
message
}
return (
<div className={classes}>
<FieldLabel
name={id}
label={label}
required={required}
requireDefault={requireDefault}
hidden={hideLabel}
/>
<div className={`${type}-field__wrapper`}>
<FieldDescription
name={id}
description={description}
hidden={hideDescription}
/>
{!isValid && <FieldErrorMessage name={id} message={message} />}
<FieldSelect
{...this.props}
value={value}
handleChange={this._handleChange}
fieldData={fieldData}
/>
{type === 'date' && <div className="date-field__icon" />}
</div>
</div>
)
}
}
export default FieldSelectWrap