1

So i have the following component

const ChartContainer: React.FC = () => {
  const [data, setData] = React.useState<unknown>([])
  const [prevMonthStamp, setPrevMonthStamp] = React.useState<number>()

  React.useEffect(() => {
    var d: any = new Date();
    d.setMonth(d.getMonth() - 30);//timestamp of x months ago
    d.setHours(0, 0, 0, 0);
    setPrevMonthStamp((d / 1000 | 0) * 1000); 
  }, [])


  React.useEffect(() => {
    let url = binanceApi
    let proxyUrl = corsProxy
    axios({
      method: 'get',
      url: proxyUrl+url
    }).then(res => {
      if (prevMonthStamp) {
        setData(res.data.filter((i: number[]) => i[0] >= prevMonthStamp))
      }
    }).catch(err => {
      console.log(err)
    })
  }, [prevMonthStamp])


  if (Array.isArray(data) && data?.length > 0) {
    return (
      <Canvas data={convertData(data)} />
    );
  } else {
    return <Spinner />
  }

}

And I notice that the api is being called twice

Supposedly on component mount, im setting prevMonthStamp, and once its set , the other useEffect is being used.

Why it happens to be used twice?

2
  • 2
    Your 2nd useEffect is running twice, 1 on mount and second time when you set setPrevMonthStamp in your first useEffect Commented Jul 1, 2021 at 15:47
  • useEffect() hook is called when the component is mounted. So, the second userEffect() is being executed once when the component is mounted, and second time when it's dependency prevMountStamp is set on the first useEffect() call. Commented Jul 1, 2021 at 15:48

2 Answers 2

2

You render once with prevMonthStamp being undefined. Two effects run as a result of this render, including the one to send the api request. Then you render again, now with prevMonthStamp equal to some number. For this second render, your api request runs again.

The fix is to get rid of the double render. Calculate the initial state of prevMonthStamp on the very first render, not in an effect after the render.

  const [prevMonthStamp, setPrevMonthStamp] = React.useState<number>(() => {
    const d: Date = new Date();
    d.setMonth(d.getMonth() - 30);//timestamp of x months ago
    d.setHours(0, 0, 0, 0);
    return (d / 1000 | 0) * 1000
  })
Sign up to request clarification or add additional context in comments.

Comments

0

This second useEffect (the one with "prevMonthStamp" dependency) is called twice. First when prevMonthStamp is undefined. Second when prevMonthStamp is updated.

You can make it a single call by assigning value to the prevMonthStamp State on the first render.

const [prevMonthStamp, setPrevMonthStamp] = React.useState<number>(() =>{
....
return (d / 1000 | 0) * 1000;
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.