React / React-Hooks:需要在React Hooks组件中运行onLoad函数

时间:2019-06-18 14:27:32

标签: javascript reactjs react-hooks

我有一个父组件,该组件的功能是在电子邮件输入字段上运行验证,并将该函数作为道具传递给实际上包含需要验证的输入字段的子组件。验证有效,我现在唯一的问题是验证不会在加载时运行,因此,即使在输入字段中预先填充了用户电子邮件,验证的默认状态仍设置为失败,因此用户必须单击进入输入字段并单击以触发onBlur函数,从而触发验证。我不确定如何使用React挂钩在加载时运行函数,因为我对使用它们仍然还很陌生。

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 &nbsp;
            </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

1 个答案:

答案 0 :(得分:1)

尝试将模糊代码粘贴到效果中。我看到您正在使用e.target.value,但是您已经使用useState明确设置了值,所以请使用inputValue

React.useEffect(() => checkIfCustomerEmailIsValid(inputValue), [])

useEffect的作用是,当第二个参数中的变量更改时,执行第一个渲染器和其他每个渲染器提供的功能。由于我们提供了一个空数组,因此它将仅在组件最初呈现时执行一次。