0

I press the onClick button and it sends the data (time and ID) to the backend.

The problem is: the backend receives the data twice instead of just one time. req.body prints the data twice. See at the bottom.

Does anyone know what am I doing wrong? When I console.log the post request, it prints only once. So, I assume the problem is somewhere in the code here.

 const Shift = (props) => {
    const [time, setTime] = useState();
    const [inOut, setInOut] = useState('');
    
const getTime = (val) =>{
    setTime(new Date().toLocaleString());
    setInOut(val);
}

const displayMessage = () => {
    switch(inOut) {
        case 'in':
            sendClockIn();
            return  <Card.Text>
                Time: {time}<br/>You have clocked in ! <br/> Have a good working day!
            </Card.Text>;
        case 'out':
            // sendClockOut();
            return <Card.Text>
                Time: {time}<br/>You have clocked out ! <br/>Enjoy the rest of the day!
            </Card.Text>;
        default:
            return <Card.Text>
                Choose one of the 2 options from above.
            </Card.Text>;
    }
}

const sendClockIn = async () => {
    let id = props.Id;
    let clock = time;
    await ApiPostgres.dataSendClockIn({id, clock});
}

return (
    <div>
        <Card style={{ width: '25rem' }}>
            <Card.Header>
                <Button variant="primary"  onClick={() => getTime('in')}>Clock In</Button>
            </Card.Header>
            <Card.Body>
                {displayMessage()}
            </Card.Body>
        </Card>
    </div>
);
};
export default Shift;

Backend:

  console.log(req.body) 

Gives me duplicate

{ id: 1, clock: '1/11/1111, 1:11:11 PM' } 
{ id: 1, clock: '1/11/1111, 1:11:11 PM' } 

Solution:

I removed sendClockIn() from displayMessage(). Then, I made a seecond switch statement in getTime(); Then, in sendClockIn() I created another to store the current time. It works as it should.

Does anyone know what is the difference? - Is it because displayMessage() renders on load and then when then onClick?

const getTime = (e, val) =>{
    e.preventDefault();
    setTime(new Date().toLocaleString());
    setInOut(val);
    switch('in') {
        case 'in':
            sendClockIn();
            break;
        default:
            break;
    }
}

const sendClockIn = async () => {
    let id = props.Id;
    let clock = new Date().toLocaleString();
    await ApiPostgres.dataSendClockIn({id, clock});
}
yaros
  • 167
  • 2
  • 13
  • Do you have `StrictMode` enabled? – Calvin Jun 16 '21 at 06:22
  • 1
    `displayMessage()` gets called on every render. If your `onClick` handler or anything else updates state (or anything else triggers a re-render), `displayMessage()` will be called. – Calvin Jun 16 '21 at 17:26

2 Answers2

1

Unfortunately I'm not able to comment yet so I'll make a post. But I would say that it might have to do with how react is handling the data change detection.

When you are initializing the setTime variable it might be triggering a change detection and rendering the view (therefore calling displayMessage). And then when the view is rendered, you are calling getTime('in'), which makes another render and therefore calls displayMessage again.

So this way it would cause 2 requests. But this is an assumption of mine.

So to test if this assumption is true, I would remove the getTime(in) and see if only one request is being made.

If it is, so your issue is related to the one linked below.

Why is my onClick being called on render? - React.js

Franco Pan
  • 128
  • 2
  • 11
  • I think you were right. I updated the solution. Can you check if that's what you meant? Thanks. – yaros Jun 16 '21 at 15:01
1

If you have StrictMode enabled, that is likely the cause of the double API calls. In development mode, it causes components to render twice to help find unexpected side effects. Additionally, it silences console methods on the second render.

You should put your function call for making an API request inside a useEffect() hook.

Calvin
  • 443
  • 3
  • 7