I have a parent component with a function that runs a validation on an email input field and passes that function as a prop down to the child component that actually contains the input field needing validation. Validations are working, the only issue I have now is that the validation doesn't run on load so even when the input field is pre populated with a user email, the validation's default state is set as failing so that a user will have to click into the input field and click out in order to trigger the onBlur function and thus the validation. I'm not sure how to run a function on load using react hooks as I'm still fairly new to using them.
Parent Component
import React, { Component, Fragment } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { Row, Col } from 'antd'
import * as actions from '../../actions'
import { tableColumnProps } from '../../propTypes'
import Section from '../../components/layout/Section'
import CustomerDetails from '../../components/orders/CustomerDetails'
import AccountDetails from '../../components/orders/AccountDetails'
import ExistingServices from '../../components/orders/ExistingServices'
import OfferBundlesFilters from '../../components/orders/OfferBundlesFilters'
import OfferBundlesTable from '../../components/orders/OfferBundlesTable'
import OffersHeader from '../../components/orders/OffersHeader'
function validateEmail(value) {
const errors = { hasError: false }
if (value === '') {
errors.email = 'Email address or Email Opt Out is required'
errors.hasError = true
return errors
}
if (!/\S+@\S+\.\S+/.test(value)) {
errors.email = 'Email address is invalid'
errors.hasError = true
return errors
}
return errors
}
export class OffersPage extends Component {
constructor(props) {
super(props)
this.state = {
customerEmail: {},
disableEmailValidation: false,
emailValidation: {
isValid: false,
validationError: ''
}
}
}
componentDidMount() {
this.props.getOffers()
}
toggleDisableInput = value => {
this.setState({ disableEmailValidation: value })
}
removeEmailValidationError = () => {
this.setState({
emailValidation: {
isValid: true,
validationError: ''
}
})
}
checkIfCustomerEmailIsValid = inputValue => {
const validationResult = validateEmail(inputValue)
if (validationResult.hasError === true) {
this.setState({
emailValidation: {
isValid: false,
validationError: validationResult.email
}
})
} else {
this.removeEmailValidationError()
}
}
getEmailValue = email => {
if (email.hasError) {
this.setState({ customerEmail: email })
}
}
render() {
const {
customer,
offers,
services,
// selectOffer,
selectedOffer = {},
offerColumns,
filters,
updateFilter,
updateCustomer
} = this.props
return (
<Fragment>
<Row gutter={48}>
<Col span={24}>
<OffersHeader
customer={customer}
onPaidByChange={updateCustomer}
/>
</Col>
</Row>
<SectionRow>
<div>
<Section title="Customer">
<CustomerDetails
customer={customer}
getEmailValue={this.getEmailValue}
checkIfCustomerEmailIsValid={this.checkIfCustomerEmailIsValid}
emailValidation={this.state.emailValidation}
disableEmailValidation={this.state.disableEmailValidation}
toggleDisableInput={this.toggleDisableInput}
removeEmailValidationError={this.removeEmailValidationError}
/>
</Section>
<Section title="Account Information">
<AccountDetails />
</Section>
</div>
<div>
<Section title="Existing Services">
<ExistingServices services={services} />
</Section>
</div>
</SectionRow>
<Row gutter={48}>
<Col span={24}>
<StyledFiltersSection title="Filters">
<OfferBundlesFilters
filters={filters}
onFilterChange={updateFilter}
/>
</StyledFiltersSection>
</Col>
</Row>
<Row gutter={48}>
<Col span={24}>
<Section title="Offers">
<OfferBundlesTable
columns={offerColumns}
bundles={offers}
viewedOfferIds={[selectedOffer.OfferId]}
onBundleSelect={this.handleSelectOffer}
/>
</Section>
</Col>
</Row>
</Fragment>
)
}
}
const mapStateToProps = state => ({
customer: state.customer.details,
offers: state.offers.all,
offerColumns: state.offers.tableColumns,
selectedOffer: state.offers.selectedOffer,
filters: Object.values(state.offers.filters),
services: state.offers.services,
pages: state.navigation
})
const mapDispatchToProps = {
getOffers: actions.getOffers,
selectOffer: actions.selectOffer,
updateFilter: actions.updateOfferFilters,
updateCustomer: actions.updateCustomer
}
OffersPage.propTypes = {
customer: PropTypes.object,
filters: PropTypes.arrayOf(PropTypes.object),
updateFilter: PropTypes.func.isRequired,
updateCustomer: PropTypes.func.isRequired,
getOffers: PropTypes.func.isRequired,
offers: PropTypes.arrayOf(PropTypes.object),
offerColumns: tableColumnProps,
selectOffer: PropTypes.func.isRequired,
selectedOffer: PropTypes.object,
services: PropTypes.object,
location: PropTypes.object,
history: PropTypes.object
}
OffersPage.defaultProps = {
customer: null,
offers: []
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(OffersPage)
Child Component
import React from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import {
Col, Row, Icon, Input, Tooltip
} from 'antd'
import Checkbox from '../elements/Checkbox'
import Markup from '../core/Markup'
const CustomerDetails = ({
customer,
checkIfCustomerEmailIsValid,
emailValidation,
toggleDisableInput,
disableEmailValidation,
removeEmailValidationError
}) => {
const { contact = {}, account = {}, site = {} } = customer || {}
const [inputValue, setInputValue] = React.useState(contact.email)
function onBlur(e) {
checkIfCustomerEmailIsValid(e.target.value)
}
function clearInput() {
setInputValue('')
}
function handleInputChange(event) {
setInputValue(event.target.value)
}
return (
<Container>
<Row>
<Col span={10}>
<h4>
PRIMARY CONTACT EMAIL
</h4>
</Col>
</Row>
<Row>
<Row>
<Col span={8}>
<StyledInput
value={inputValue}
onChange={handleInputChange}
disabled={disableEmailValidation}
onBlur={onBlur}
isError={!emailValidation.isValid}
/>
{!emailValidation.isValid && (
<ErrorDiv>{emailValidation.validationError}</ErrorDiv>
)}
</Col>
<Col span={2} />
<Col span={8}>
<StyledCheckbox
onChange={handleOptOut}
checked={disableEmailValidation}
isError={!emailValidation.isValid}
/>{' '}
EMAIL OPT OUT{' '}
</Col>
</Row>
</Container>
)
}
CustomerDetails.propTypes = {
customer: PropTypes.object,
emailValidation: PropTypes.object,
checkIfCustomerEmailIsValid: PropTypes.func,
toggleDisableInput: PropTypes.func
}
CustomerDetails.defaultProps = {
customer: {}
}
const ErrorCheckbox = ({ isError, ...remainingProps }) => (
<Checkbox {...remainingProps} />
)
const ErrorInput = ({ isError, ...remainingProps }) => (
<Input {...remainingProps} />
)
const StyledCheckbox = styled(ErrorCheckbox)`
&&& {
background: white;
input + span {
width: 35px;
height: 35px;
border: 2px solid
${({ theme, isError }) =>
isError ? theme.colors.danger : theme.colors.black};
}
input + span:after {
width: 12.5px;
height: 20px;
}
input:focus + span {
width: 35px;
height: 35px;
}
}
`
const StyledInput = styled(ErrorInput)`
max-width: 100%;
background: white;
&&& {
border: 2px solid
${({ theme, isError }) =>
isError ? theme.colors.danger : theme.colors.black};
border-radius: 0px;
height: 35px;
}
`
ErrorInput.propTypes = {
isError: PropTypes.bool
}
ErrorCheckbox.propTypes = {
isError: PropTypes.bool
}
const ErrorDiv = styled.div`
color: #d11314;
`
const ErrorContainer = styled.div`
span {
text-align: center;
}
`
export default CustomerDetails
useEffect(() => {}, [])where the function is what you want to execute. This is the same as callingcomponentDidMount()checkIfCustomerEmailIsValidin my parent component that takes the value from input and runs a validation check. I currently have that set as the function that runs onBlur on my input field. The problem I'm having is that because that function only runs onBlur it sets the input field as having errors even when the field pre populates with an email address from an API. I need to find a way to run validation for that input when everything initially loads