Search code examples
javascriptreactjsviterechartsswc-compiler

Recharts data doesn't load unless I hit ctrl+s


I created a LineChart using recharts and I'm pulling data using axios from a db.json file hosted locally by json-server. Every time I load the page or reload the chart doesn't show up. Only when I hit ctrl+s to save my file and trigger re-render does the chart show up. How do I get the chart to show up on initial page load?

I used Vite with SWC to initialize the project and versions are: [email protected], [email protected], [email protected]

Chart code:

<ResponsiveContainer width="100%" height={270}>
        <LineChart
          width={600}
          height={300}
          data={monthlyData}
          margin={{
            left: -20,
          }}
        >
          <CartesianGrid vertical={false} />
          <Tooltip />
          <XAxis axisLine={false} dataKey="name" tickSize={0} tickMargin={10} />
          <YAxis
            axisLine={false}
            domain={[0, maxY]}
            tickCount={maxY / 100 + 1}
            tickSize={0}
            tickMargin={10}
          />
          <Line
            type="monotone"
            dataKey="user"
            strokeWidth={2}
            stroke="#9BDD7C"
            dot={false}
          />
          <Line
            type="monotone"
            dataKey="guest"
            strokeWidth={2}
            stroke="#E9A0A0"
            dot={false}
          />
        </LineChart>
      </ResponsiveContainer>

This is how I'm fetching the data:

const getActivity = async (index) => {
    const res = await api.get("/activity");
    const data = res?.data;
    setYearlyData(data);
    setMonthlyData(yearlyData[index]);
  };

  useEffect(() => {
    getActivity(0);
  }, []);

Solution

  • setMonthlyData(yearlyData[index]) is wrong.

    When you do const [yearlyData, setYearlyData] = useState([]), yearlyData is immutable. What setYearlyData does is not change yearlyData, but make it so that the next time your component runs, it will read the new value for yearlyData. It will also queue up your component to run (i.e. re-render) when the browser gets the chance.

    That means that at this time yearlyData is still undefined. You should use setMonthlyData(data[index]) if you want to use the data you just got.

    BTW this issue can be avoided if you make the initial state of yearlyData null. Then JavaScript will let you know there is an error with yearlyData[index].

    If I guessed this issue wrong, you can try to debug further by inserting

    console.log('yearlyData', yearlyData)
    console.log('monthlyData', monthlyData)
    

    after your useState, and change your getActivity to:

    const getActivity = async (index) => {
      console.log('fetching')
      const res = await api.get("/activity");
      const data = res?.data;
      console.log('data', data)
      setYearlyData(data);
      console.log('yearlyData', yearlyData)
      setMonthlyData(yearlyData[index]);
    };
    

    That should show you what's going on.