当前位置: 首页 > 面试题库 >

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

尉迟京
2023-03-14
问题内容

我有一个想法,可能是因为我正在做一些样式设计来更改单选按钮,但是我不确定。我正在设置一个onClick事件,该事件两次调用了我的函数。我已删除它以确保它没有在其他地方被触发,并且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>
    )
  }
}

问题答案:

问题是与html相关,而不是与React相关。默认情况下,单击标签还将触发与其关联的输入元素的onClick事件。在您的情况下,onClick事件将附加到标签和输入。因此,通过单击标签,事件将触发两次:一次针对标签,一次针对与其相关的输入。

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



 类似资料:
  • 编辑:由于代码剪贴不会重现错误-这里有一个指向github repo的链接:(代码远未完成) https://github.com/altruios/clicker-game 我现在已经在两台计算机上运行了它——这两台计算机都有相同的行为,而代码剪报并没有显示出来。 因此,我正在构建一个clicker游戏来学习react,我不明白为什么这段代码会以这种方式运行: 在主应用程序中,我有以下功能: 那

  • 正如我的类名所暗示的那样:如果我的类是迭代器的实例,我想测试一下。因此,我想知道,如果它只需要实现接口就可以这样做,似乎就足够了。 然而,当我通过JUNIT Test运行以下类时,我得到了以下控制台输出: 似乎类构造函数被调用了两次!但是我不知道第二次调用来自哪里。我已经测试了“if”参数的变体以排除有故障,例如 然而,它在所有3种情况下都被调用了。因此,我假设Unit Test首先尝试,需要为自

  • 问题内容: 在以下示例中,当单击时,将显示而不是。为什么?您将如何解决? 问题答案: React的对帐算法假定没有相反的信息,如果自定义组件出现在后续渲染的同一位置,则它与以前的组件相同,因此将重用前一个实例,而不是创建一个新实例。 如果要实现,则会看到被调用。 不同的节点类型 元素不太可能生成看起来像a 会生成的DOM 。无需花费时间尝试匹配这两种结构,React只是从头开始重建树。 作为推论,

  • 问题内容: 代码很简单: 您会看到这里有一个函数,我们只在体内调用它一次。但是在控制台中,它打印两次: 您可以在此处观看现场演示:http : //plnkr.co/edit/tb8RpnBJZaJ73V73QISC?p=preview 为什么该函数已被调用两次? 问题答案: 在AngularJS中,用大括号括起来的任何东西都是一个在摘要循环 中至少 被求值 一次 的表达式。 __ Angular

  • 我是新来的反应,什么来理解为什么console.log在渲染函数内部被调用两次? 如果我不从组件扩展,而是使用功能,控制台只打印一次

  • 基本上,这就是我正在做的 1) 将AlarmManager设置为执行广播接收器(BCR) 2) 从BCR启动MyActivity 3)如果我的活动没有打开,请打开屏幕 出于某种原因,我注意到当MyActivity打开时,它的流程如下所示: onCreate/onNewIntent- 我不知道为什么它会马上暂停。我注意到这只发生在屏幕被标志打开时。有人知道为什么会这样吗?有什么办法可以防止这种行为吗