Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my function being called twice in React?

I have an idea that this may be because I am doing some styling things to change my radio button, but I am not sure. I am setting an onClick event that is calling my function twice. I have removed it to make sure it wasn't being triggered somewhere else and the onClick seems to be the culprit.

<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> 

my function is just for now a simple console log of the shipping option:

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

If there isn't any reason you see here why this would happen I can post the rest of the code, but there is a lot and I don't think it would pertain to this, but I think this is a good starting place.

Full code:

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>     )   } } 
like image 659
Taylor Austin Avatar asked Jun 12 '18 14:06

Taylor Austin


People also ask

Why is my React function running twice?

If your application is acting weird after you updated to React 18, this is simply due to the fact that the original behavior of the useEffect hook was changed to execute the effect twice instead of once.

Why is API getting called twice in React?

So you've upgraded to React 18, enabled strict mode, and now all of your useEffects are getting called twice. Which would normally be fine, but you have API calls in your useEffects so you're seeing double traffic in development mode.

How do you handle double click in React?

To handle double click events in React:Add an onClick prop to the element. Use the detail property on the event object to get the click count. If the click count is equal to 2, handle the double click event.


1 Answers

Its because your app component is a wrap in StrictMode.

<React.StrictMode>   <App /> </React.StrictMode>, 

If you are using create-react-app then it is found in index.js

It is expected that setState updaters will run twice in strict mode in development. This helps ensure the code doesn't rely on them running a single time (which wouldn't be the case if an async render was aborted and later restarted). If your setState updaters are pure functions (as they should be) then this shouldn't affect the logic of your application.

https://github.com/facebook/react/issues/12856#issuecomment-390206425

like image 65
Nisharg Shah Avatar answered Oct 09 '22 05:10

Nisharg Shah