javascript - react / react Hook : Need to run a function onLoad within React Hooks component

标签 javascript reactjs react-hooks

我有一个父组件,其函数在电子邮件输入字段上运行验证,并将该函数作为 Prop 传递给实际包含需要验证的输入字段的子组件。验证正在工作,我现在唯一的问题是验证不会在加载时运行,因此即使输入字段预先填充了用户电子邮件,验证的默认状态也设置为失败,因此用户必须单击进入输入字段并单击以触发 onBlur 功能,从而触发验证。我不确定如何使用 react 钩子(Hook)在加载时运行函数,因为我对使用它们还是很陌生。
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

最佳答案

尝试将 on blur 代码粘贴到效果中。我看到你正在使用 e.target.value ,但您已经使用 useState 显式设置了值, 所以使用 inputValue :

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

useEffect 所做的是在第二个参数中的变量发生变化时执行第一次渲染和所有其他渲染上提供的函数。由于我们提供了一个空数组,它只会执行一次——在组件最初呈现时。

关于javascript - react / react Hook : Need to run a function onLoad within React Hooks component,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56651399/

相关文章:

javascript - 在模态弹出窗口内插入图像

javascript - 使用严格模式 pragma 时如何声明全局变量

javascript - Chrome 扩展程序不工作

javascript - 如何在 recharts 中按 y 轴上的固定数量分隔值

mysql - 在 react 中显示图像数组?

javascript - 带有钩子(Hook)的 Socket.io 和 React 的奇怪行为

javascript - jquery使用正则表达式替换 anchor 中的字符串

javascript - 警告 : validateDOMNesting(. ..):<a> 不能作为 <a> 的后代出现

javascript - React 检测到 Navigation 调用的 Hooks 的顺序发生了变化

javascript - 如何在 React useEffect hook 中获取更新的状态值