React에서 기능이 두 번 호출되는 이유는 무엇입니까?
라디오 버튼을 바꾸기 위해 스타일링을 하고 있기 때문인 것 같습니다만, 잘 모르겠습니다.함수를 두 번 호출하는 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>
)
}
}
그 이유는 당신의app
컴포넌트는 랩인입니다.StrictMode
.
<React.StrictMode>
<App />
</React.StrictMode>,
사용하시는 경우
create-react-app
그리고 그것은 에서 발견됩니다.index.js
할 것으로 예상된다setState
업데이트 프로그램이 2회 실행됩니다.strict mode
개발중입니다.이렇게 하면 코드가 한 번 실행되는 데 의존하지 않습니다(비동기 렌더가 중단되었다가 나중에 재시작된 경우에는 해당되지 않음).만약 당신이setState
업데이트 프로그램은 순수 함수이므로 응용 프로그램의 로직에는 영향을 주지 않습니다.
https://github.com/facebook/react/issues/12856#issuecomment-390206425
이 문제는 리액트와 관련된 것이 아니라 html과 관련된 것입니다.기본적으로 라벨을 클릭하면 라벨과 관련된 입력 요소의 onClick 이벤트도 트리거됩니다.이 경우 onClick 이벤트는 라벨과 입력 모두에 첨부됩니다.따라서 라벨을 클릭하면 이벤트가 두 번(라벨과 관련된 입력에 대해 한 번) 실행됩니다.
편집: onClick 청취자를 입력에 연결하면 문제를 해결할 수 있습니다.
를 사용하여 두 번 호출을 방지하다e.preventDefault()
.
changeShipping(e){
e.preventDefault();
console.log('clicked');
}
e.stopPropagation()
탐구할 가치가 있습니다.onMouseDown 이벤트를 처리하고 있었는데 prevent Default로 인해 여러 콜이 차단되지 않았습니다.
https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation
이 경우 중복 콜을 피하기 위해 둘 다 필요합니다.
<React.StrictMode>
<App />
</React.StrictMode>
니샤르그 샤 출신
e.preventDefault();
암루스 출신
또한 기능 컴포넌트에 대해 useEffect() 메서드가 2회 호출되는 경우 bcoz입니다.FC(기능 컴포넌트) 및 의존성 목록에서 바인드하기 위해 사용되는 모든 메서드는 useEffect가 1개뿐입니다.변경 후 다음과 같습니다.
useEffect(() => {
console.log("AFTER CHANGE : ", data) // move to below method
handleSubmit.bind(this);
handleCancel.bind(this);
testChange.bind(this);
}, [
data // move to below method
]);
useEffect(() => {
console.log("AFTER CHANGE : ", data)
}, [data]);
- , 것은 의존자 리스트가 없습니다.
bindings
-
onChange()
의 dependencyList가
이게 도움이 됐으면 좋겠다.해피 코딩...
언급URL : https://stackoverflow.com/questions/50819162/why-is-my-function-being-called-twice-in-react
'programing' 카테고리의 다른 글
jPOST 매개 변수로 문자열 전송 쿼리 (0) | 2023.03.19 |
---|---|
오류: 소스 경로가 없습니다. resources\android\icon\drawable-hdpi-icon.png (0) | 2023.03.19 |
iOS 디바이스의 Safari에서 손상된 이미지를 로드하고 있습니다(Wordpress 사이트). (0) | 2023.03.14 |
TypeScript 해시맵/사전 인터페이스 (0) | 2023.03.14 |
구체적으로 어떤 JS 엔진에서 Lower Case 및 To Upper Case 로케일에 민감합니까? (0) | 2023.03.14 |