代码之家  ›  专栏  ›  技术社区  ›  Taylor Austin

为什么我的函数在react中被调用两次?

  •  6
  • Taylor Austin  · 技术社区  · 6 年前

    我有一个想法,这可能是因为我正在做一些造型的事情来改变我的收音机按钮,但我不确定。我正在设置一个onclick事件,它两次调用我的函数。我已经移除了它,以确保它不会在其他地方被触发,而一次点击似乎是罪魁祸首。

    <div
      className="CheckboxContainer"
      onClick={() =>
        this.changeShipping({ [k]: i })
      }
    >
      <label>
        <div className="ShippingName">
          {shipOption.carrier
            ? shipOption.carrier.serviceType
            : null}{' '}
          {shipOption.name}
        </div>
        <div className="ShippingPrice">
          ${shipOption.amount}
        </div>
        <input
          type="radio"
          value={i}
          className="ShippingInput"
          onChange={() =>
            this.setState({
              shippingOption: {
                ...this.state.shippingOption,
                [k]: i
              }
            })
          }
          checked={
            this.state.shippingOption[k] === i
              ? true
              : false
          }
        />
        <span className="Checkbox" />
      </label>
    </div>
    

    我的功能只是一个简单的控制台日志,其中包含发货选项:

    changeShipping(shipOption){
     console.log('clicked') // happening twice 
    }
    

    如果没有任何原因,你可以在这里看到为什么会发生这种情况,我可以发布其余的代码,但有很多,我认为这与此无关,但我认为这是一个很好的开始。

    完整代码:

    import React, { Component } from 'react'
    import fetch from 'isomorphic-fetch'
    import { Subscribe } from 'statable'
    import { FoldingCube } from 'better-react-spinkit'
    
    import styles from './styles'
    import { cost, cartState, userInfo, itemState, Api } from '../../state'
    import { removeCookies, resetCart } from '../../../injectState'
    
    export default class ShippingOptions extends Component {
      constructor(props) {
        super(props)
        this.state = {
          shippingOption: {}
        }
    
        this.changeShipping = this.changeShipping.bind(this)
      }
    
      async changeShipping(shipOption) {
        const shipKey = Object.keys(shipOption)[0]
        // if (userInfo.state.preOrderInfo.setShip[shipKey] === shipOption[shipKey]) {
        //   return
        // }
        let updatedShipOption = {}
        Object.keys(shipOption).forEach(k => {
          updatedShipOption = userInfo.state.preOrderInfo.setShip
            ? { ...userInfo.state.preOrderInfo.setShip, [k]: shipOption[k] }
            : shipOption
        })
    
        userInfo.setState({
          preOrderInfo: {
            ...userInfo.state.preOrderInfo,
            setShip: updatedShipOption
          }
        })
    
        // Make request to change shipping option
        const { preOrderInfo } = userInfo.state
    
        const shippingRes = await fetch(Api.state.api, {
          body: JSON.stringify(preOrderInfo),
          method: 'POST'
        })
          .then(res => res.json())
          .catch(err => {
            let error = ''
            if (
              err.request &&
              (err.request.status === 404 || err.request.status === 502)
            ) {
              error = `Error with API: ${err.response.statusText}`
            } else if (err.request && err.request.status === 0 && !err.response) {
              error =
                'Something went wrong with the request, no response was given.'
            } else {
              error = err.response || JSON.stringify(err) || err
            }
            cartState.setState({
              apiErrors: [error],
              loading: false
            })
          })
        console.log(shippingRes)
      }
    
      async componentDidMount() {
        if (cartState.state.tab === 2) {
          const { shipping } = userInfo.state
          const { items, coupon } = itemState.state
          let updated = { ...shipping }
          const names = updated.shippingFullName.split(' ')
          updated.shippingFirst = names[0]
          updated.shippingLast = names[1]
          delete updated.shippingFullName
          updated.site = cartState.state.site
          updated.products = items
          updated.couponCode = coupon
          updated.addressSame = userInfo.state.addressSame
          cartState.setState({
            loading: true
          })
          const shippingRes = await fetch(Api.state.api, {
            body: JSON.stringify(updated),
            method: 'POST'
          })
            .then(res => res.json())
            .catch(err => {
              let error = ''
              if (
                err.request &&
                (err.request.status === 404 || err.request.status === 502)
              ) {
                error = `Error with API: ${err.response.statusText}`
              } else if (err.request && err.request.status === 0 && !err.response) {
                error =
                  'Something went wrong with the request, no response was given.'
              } else {
                error = err.response || JSON.stringify(err) || err
              }
              cartState.setState({
                apiErrors: [error],
                loading: false
              })
            })
          console.log(shippingRes)
          return
          shippingRes.products.forEach(product => {
            const regexp = new RegExp(product.id, 'gi')
            const updatedItem = items.find(({ id }) => regexp.test(id))
    
            if (!updatedItem) {
              console.warn('Item not found and being removed from the array')
              const index = itemState.state.items.indexOf(updatedItem)
              const updated = [...itemState.state.items]
              updated.splice(index, 1)
              itemState.setState({
                items: updated
              })
              return
            }
            updatedItem.price = product.price
            itemState.setState({
              items: itemState.state.items.map(
                item => (item.id === product.id ? updatedItem : item)
              )
            })
          })
          updated.shippingOptions = shippingRes.shippingOptions
          Object.keys(updated.shippingOptions).forEach(k => {
            this.setState({
              shippingOption: { ...this.state.shippingOption, [k]: 0 }
            })
            updated.setShip = updated.setShip
              ? { ...updated.setShip, [k]: 0 }
              : { [k]: 0 }
          })
    
          updated.success = shippingRes.success
          updated.cartId = shippingRes.cartId
          updated.locations = shippingRes.locations
          userInfo.setState({
            preOrderInfo: updated
          })
          cost.setState({
            tax: shippingRes.tax,
            shipping: shippingRes.shipping,
            shippingOptions:
              Object.keys(updated.shippingOptions).length > 0
                ? updated.shippingOptions
                : null
          })
          cartState.setState({
            loading: false,
            apiErrors: shippingRes.errors.length > 0 ? shippingRes.errors : null
          })
          if (shippingRes.errors.length > 0) {
            removeCookies()
            shippingRes.errors.forEach(err => {
              if (err.includes('CRT-1-00013')) {
                itemState.setState({ coupon: '' })
              }
            })
          }
        }
      }
    
      render() {
        return (
          <Subscribe to={[cartState, cost, itemState]}>
            {(cart, cost, itemState) => {
              if (cart.loading) {
                return (
                  <div className="Loading">
                    <div className="Loader">
                      <FoldingCube size={50} color="rgb(0, 207, 255)" />
                    </div>
                  </div>
                )
              }
              if (cart.apiErrors) {
                return (
                  <div className="ShippingErrors">
                    <div className="ErrorsTitle">
                      Please Contact Customer Support
                    </div>
                    <div className="ErrorsContact">
                      (contact information for customer support)
                    </div>
                    <div className="Msgs">
                      {cart.apiErrors.map((error, i) => {
                        return (
                          <div key={i} className="Err">
                            {error}
                          </div>
                        )
                      })}
                    </div>
                    <style jsx>{styles}</style>
                  </div>
                )
              }
              return (
                <div className="ShippingOptionsContainer">
                  <div className="ShippingOptions">
                    {cost.shippingOptions ? (
                      <div className="ShipOptionLine">
                        {Object.keys(cost.shippingOptions).map((k, i) => {
                          const shipOptions = cost.shippingOptions[k]
                          const updatedProducts =
                            shipOptions.products.length === 0
                              ? []
                              : shipOptions.products.map(product =>
                                  itemState.items.find(
                                    item => item.id === product.id
                                  )
                                )
                          return (
                            <div className="ShippingInputs" key={i}>
                              {shipOptions.options.map((shipOption, i) => {
                                return (
                                  <div className="ShippingSection" key={i}>
                                    <div className="SectionTitle">
                                      4. {shipOption.name} Shipping Options
                                    </div>
                                    {updatedProducts.length > 0 ? (
                                      <div className="ShippingProducts">
                                        {updatedProducts.map((product, i) => (
                                          <div key={i}>
                                            for{' '}
                                            {shipOption.name === 'Freight'
                                              ? 'Large'
                                              : 'Small'}{' '}
                                            {product.name} from{' '}
                                            {k.charAt(0).toUpperCase() + k.slice(1)}
                                          </div>
                                        ))}
                                      </div>
                                    ) : null}
                                    <div
                                      className="CheckboxContainer"
                                      onClick={() =>
                                        this.changeShipping({ [k]: i })
                                      }
                                    >
                                      <label>
                                        <div className="ShippingName">
                                          {shipOption.carrier
                                            ? shipOption.carrier.serviceType
                                            : null}{' '}
                                          {shipOption.name}
                                        </div>
                                        <div className="ShippingPrice">
                                          ${shipOption.amount}
                                        </div>
                                        <input
                                          type="radio"
                                          value={i}
                                          className="ShippingInput"
                                          onChange={() =>
                                            this.setState({
                                              shippingOption: {
                                                ...this.state.shippingOption,
                                                [k]: i
                                              }
                                            })
                                          }
                                          checked={
                                            this.state.shippingOption[k] === i
                                              ? true
                                              : false
                                          }
                                        />
                                        <span className="Checkbox" />
                                      </label>
                                    </div>
                                  </div>
                                )
                              })}
                            </div>
                          )
                        })}
                      </div>
                    ) : null}
                  </div>
                  <style jsx>{styles}</style>
                </div>
              )
            }}
          </Subscribe>
        )
      }
    }
    
    2 回复  |  直到 6 年前
        1
  •  5
  •   Halcyon    6 年前

    问题与HTML相关,而不是与反应相关。默认情况下,单击标签还会触发与其关联的输入元素的onclick事件。在您的例子中,onclick事件同时附加到标签和输入上。因此,通过单击标签,事件被触发两次:一次是针对标签,一次是针对与之关联的输入。

    编辑:将onclick侦听器附加到输入是解决该问题的可能方法

        2
  •  4
  •   Amruth    6 年前

    使用阻止两次呼叫 e.preventDefault() .

    changeShipping(e){
       e.preventDefault();
       console.log('clicked') // happening twice 
    }