1

I want to track when user click the button, and send the record to server.

and I am thinking where should I put the "send the record to server" logic in my component

to put it inside onClick handler or move it to useEffect

first version:

function Btn() {
  return (
    <Button onClick={(e) => {
      // is doing side effect inside onClick handler a good practice ?
      sendRecordToServer({ btnName: 'btn1' });
    }}>
      click & track me
    </Button>
  )
}

then I noticed the doc of useEffect said

Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React’s render phase). Doing so will lead to confusing bugs and inconsistencies in the UI.

so my second version:

function Btn() {
  // introduce a new state
  const [track, setTrack] = useState()

  // doing side effect inside useEffect
  useEffect(() => {
    if (track) {
      sendRecordToServer(track);
    }
  }, [track])

  return (
    <Button onClick={(e) => {
      // has to be a object to make the effect can re-run, not simple string
      setTrack({
        btnName: 'btn1'
      })
    }}>
      click & track me
    </Button>
  )
}

Can someone tell me which version is nicer ?

Littlee
  • 3,791
  • 6
  • 29
  • 61

1 Answers1

0

I would go for the first one. In the second one, you are introducing a new state just to use useEffect which makes the code harder to read. As for the quote from the React documentation: they wrote that you shouldn't do any logging in function component body which means that you shouldn't do any logging etc. in Btn() function directly:

function Btn() {
    sendRecordToServer(); // BAD!
    ...

    return (
        ...
    )
}

On the other hand, if you already had some state - let's say for currentSliderIndex and you wanted to log the currently viewed slide then I think it would be better to use useEffect. Let's take a look at the following code:

const SliderComponent = (props) => {
    const [currentSlideIndex, setCurrentSlideIndex] = useState(0);

    function onPrevClick() {
        setCurrentSlideIndex(currentIndex => prevIndex - 1);
    }

    function onNextClick() {
        setCurrentSlideIndex(currentIndex => prevIndex + 1);
    }

    return (
        <div className="slider"}>
            <button onClick={onPrevClick} className="slider__navigation slider__navigation--prev" />
            <div className="slider__list">...</div>
            <button onClick={onNextClick} className="slider__navigation slider__navigation--next" />
        </div>
    )
}

For the above, if you wanted to track the currently viewed slideIndex then it would be better to add useEffect so that you don't have to place your logging in 2 places (in onPrevClick and onNextClick). But if you wanted to track slick on prev/next slide navigation button click then it would be best to put that directly into onPrevClick/onNextClick funtions.

So to summarize - it depends :P In your case I would go for the first option as it's more readable and doesn't introduce additional boilerplate.

Wojciech Dynus
  • 911
  • 5
  • 11