2

I've been using Refine to build a dashboard application.

The majority of the pages work well with the data fetching capabilities provided by the Refine framework. However, I encountered an issue when trying to implement custom data fetching for specific pages.

Below is the problematic page component:

import { Box, Card, Grid, Stack, Typography } from "@mui/material";
import { useApiUrl, useParsed } from "@refinedev/core";
import { Show } from "@refinedev/mui";
import { ICampaignStatistics, ISetting } from "../../interfaces";
import React, { useEffect, useState } from "react";

export const CampaignShow: React.FC = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [setting, setSetting] = useState<ISetting | null>(null);
  const [stats, setStats] = useState<ICampaignStatistics | null>(null);

  const apiUrl = useApiUrl();
  const { id } = useParsed();

  useEffect(() => {
    const headers = {
      "Access-Control-Allow-Origin": "*",
      Authorization: `Bearer ${localStorage.getItem("access_token")}`,
    };
    const controller = new AbortController();
    const signal = controller.signal;

    (async () => {
      try {
        const settingRes = await fetch(`${apiUrl}/setting`, {
          headers,
          signal,
        });
        const settingData = await settingRes.json();
        setSetting(settingData?.data as unknown as ISetting);

        // It prints the correct data here!
        console.log(statsData);

        const statsRes = await fetch(`${apiUrl}/campaigns/${id}/stats`, {
          headers,
          signal: controller.signal,
        });
        const statsData = await statsRes.json();
        setStats(statsData?.data as unknown as ICampaignStatistics);

        setIsLoading(false);
      } catch (e) {
        setIsLoading(false);
        console.log(e);
      }
    })();

    return () => controller.abort("");
  }, []);

  if (isLoading) {
    return <div>Loading...</div>;
  }

  // It always prints null(initial state) or undefined (which should be the updated data - setting)
  console.log(setting);

  return (
    <Show>
      {stats && stats.whiteLocked}
      {setting && (
        <Grid container spacing={2}>
          // ... snip ...
        </Grid>
      )}
    </Show>
  );
};

I believe I'm missing something very simple, but I don't have any clue what it could be.

Please help me.

1
  • I was able to work around the problem by using the useCustom hook provided by Refine. Actually, it's an excellent solution for my specific use case. However, my question still remains because useEffect should have no reason to not do its job well. Commented May 13 at 19:15

1 Answer 1

1

First, I suggest you useCustom hook. This is exactly designed for this purpose. If for some reason useCustom doesn't work for you, please open an issue on GitHub and tell us about its limitations. This will help Refine improve a lot. 🙌

The code looks fine, but I suggest a couple of debug suggestions:

  • We need to add id to the useEffect dependency. If id is undefined in the first render, we cannot fetch the data.
  • Is settingData?.data correct? I suggest you look at the response of the fetch. Maybe the value is returned in another field.

It works with this way but I used my own API and I strongly recommend using useCustom

import { useParsed } from "@refinedev/core";
import React, { useEffect, useState } from "react";

export const PostShow: React.FC = () => {
    const [isLoading, setIsLoading] = useState(true);
    const [setting, setSetting] = useState<any>(null);
    const [stats, setStats] = useState<any>(null);

    const { id } = useParsed();

    useEffect(() => {
        const headers = {
            "Access-Control-Allow-Origin": "*",
        };
        const controller = new AbortController();
        const signal = controller.signal;

        (async () => {
            try {
                const settingRes = await fetch(
                    "https://api.fake-rest.refine.dev/posts?_end=10&_start=0",
                    {
                        headers,
                        signal,
                    },
                );
                const settingData = await settingRes.json();
                setSetting(settingData?.data as unknown as any);

                const statsRes = await fetch(
                    `https://api.fake-rest.refine.dev/posts/${id}`,
                    {
                        headers,
                        signal: controller.signal,
                    },
                );
                const statsData = await statsRes.json();
                setStats(statsData?.data as unknown as any);

                console.log({ statsData, settingData });

                setIsLoading(false);
            } catch (e) {
                setIsLoading(false);
                console.log(e);
            }
        })();

        return () => {
            return controller.abort("");
        };
    }, [id]);

    // works
    console.log({ stats, setting, id, isLoading });

    if (isLoading) {
        return <div>Loading...</div>;
    }

    return <h1>Testing</h1>;
};
1
  • I don't remember if I have already tried adding the ID as a dependency. I will try it soon when I have some time. Regarding your second bullet point, yes, it is correct on my end. Thank you! Commented Jun 4 at 17:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.