Search code examples
reactjsreact-hooksuse-effect

ReactJS Having trouble setState on UseEffect when dependencies change


I'm trying to setState on dischargeMeasureInput.point2D.speed when users input both time and round. It's working fine if not 'HOLDING' a key when I change time or round value, but when I HOLD backspace or any other keys on <Input {time,round} /> it's causing an infinite loop. Does anyone know how to fix this?

const [dischargeMeasureInput, setDischargeMeasureInput] = useState({
        discOperatId: null, discMeasureId: null,
        orderNo: '1', depthPoint: '3', depth: null, distant: null,
        point2D: { surfaceD: null, time: null, round: null, speed: null }
})    

useEffect(() => {
        if (dischargeMeasureInput.point2D.time && dischargeMeasureInput.point2D.round) {
               axios()...
                .then(res => {
                    if (res.data) {
                        setDischargeMeasureInput({ ...dischargeMeasureInput, point2D: { ...dischargeMeasureInput.point2D, speed: res.data.velocityPoint1 } })
                    }
                    else {
                        setDischargeMeasureInput({ ...dischargeMeasureInput, point2D: { ...dischargeMeasureInput.point2D, speed: null } })
                    }
                })
                .catch(err => {
                    console.log(err)
                })
        }

}, [dischargeMeasureInput.point2D.time, dischargeMeasureInput.point2D.round])

//child Component
<Input value={props.dischargeMeasureInput.point2D.time}
       onChange={(e) => props.setDischargeMeasureInput({ ...props.dischargeMeasureInput, point2D: { ...props.dischargeMeasureInput.point2D, time: e.target.value } })}/>
                
<Input value={props.dischargeMeasureInput.point2D.round}
       onChange={(e) => props.setDischargeMeasureInput({ ...props.dischargeMeasureInput, point2D: { ...props.dischargeMeasureInput.point2D, round: e.target.value } })} />
                
<Input value={props.dischargeMeasureInput.point2D.speed}
       onChange={(e) => props.setDischargeMeasureInput({ ...props.dischargeMeasureInput, point2D: { ...props.dischargeMeasureInput.point2D, speed: e.target.value } })} />

Here's a short .gif


Solution

  • Okay I figured it out, it seems there's a race condition. I just have to add bool flag before setState. This link help me out https://medium.com/hackernoon/avoiding-race-conditions-when-fetching-data-with-react-hooks-220d6fd0f663

    useEffect(() => {
        let canceled = false
        
        if(!canceled)
         setDischargeMeasureInput({ ...dischargeMeasureInput, point2D: { ...dischargeMeasureInput.point2D, speed: res.data.velocityPoint1 } })
        }
        
        //and cleanup function
        return () => (canceled = true)
    })