Next.js Discord

Discord Forum

Data Loading

Unanswered
Blue Picardy Spaniel posted this in #help-forum
Open in Discord
Blue Picardy SpanielOP
# Code
"use client";

import { Loader2, RefreshCw } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { User } from "@db/schema";
import { getUserGuilds } from "@/lib/discord-api";
import { set } from "@/app/dashboard/guilds-slice";
import { useDispatch } from "react-redux";
import { useState } from "react";
import { useToast } from "@/components/ui/use-toast";

export default function RefreshGuilds({ user }: { user: User }) {
  const [loading, setLoading] = useState(false);
  const dispatch = useDispatch();
  const { toast } = useToast();

  async function refreshGuilds() {
    setLoading(true);

    if(!user) {
      setLoading(false);
      return toast({ description: "Something went wrong!", variant: "destructive" });
    }

    getUserGuilds().then(userGuilds => {
      if(userGuilds) {
        dispatch(set(userGuilds));
        toast({ description: "Guilds refreshed" });
      }

      if(!userGuilds) toast({ description: "Something went wrong!", variant: "destructive" });
      setLoading(false);
    });
  }

  return (
    <form action={refreshGuilds}>
      <Button variant="outline" disabled={loading}>
        {loading ? <Loader2 className="mr-2 h-5 w-5 animate-spin" /> : <RefreshCw className="mr-2 h-5 w-5" />}
        <span className="text-base">Refresh</span>
      </Button>
    </form>
  );
}

# Issue
The loader never shows.
# Notes
- If I add a wait, the loader shows.
- true is printed twice and false is printed twice when I click the button.

12 Replies

Sloth bear
toast({ description: "Guilds refreshed" });

Does this toast pop up?
U want the loading state to work?
'use client'
 
import { useFormStatus } from 'react-dom'
 
export function SubmitButton() {
  const { pending } = useFormStatus()
 
  return (
    <button type="submit" disabled={pending}>
      Add
    </button>
  )
}
@Blue Picardy Spaniel yeah
Sloth bear
Try to force re-render
setLoading(true);
await new Promise(resolve => setTimeout(resolve, 0));
getUserGuilds().then(userGuilds => {
   if (userGuilds) {
     dispatch(set(userGuilds));
     toast({ description: "Guilds refreshed" });
   } else {
     toast({ description: "Something went wrong!", variant: "destructive" });
   }
   setLoading(false);
});
Sloth bear
Or you can do it like that:
getUserGuilds().then(userGuilds => {
   setTimeout(() => {
      if (userGuilds) {
        dispatch(set(userGuilds));
        toast({ description: "Guilds refreshed" });
      } else {
        toast({ description: "Something went wrong!", variant: "destructive" });
      }
      setLoading(false);
   }, 500);
});
If it did helped you don't forget to Mark Solution
Blue Picardy SpanielOP
this isn't really the proper way to do it tho
i want to do it the way its intended instead of using workarounds
Sloth bear
Ahm try this then:
export default function RefreshGuilds({ user }: { user: User }) {
    const [loading, setLoading] = useState(false);
    const dispatch = useDispatch();
    const { toast } = useToast();
  
    const refreshGuilds = async () => {
      setLoading(true);
  
      if (!user) {
        setLoading(false);
        return toast({ description: "Something went wrong!", variant: "destructive" });
      }
  
      try {
        const userGuilds = await getUserGuilds();
        if (userGuilds) {
          dispatch(set(userGuilds));
          toast({ description: "Guilds refreshed" });
        } else {
          toast({ description: "Something went wrong!", variant: "destructive" });
        }
      } catch (error) {
        toast({ description: "Failed to fetch guilds!", variant: "destructive" });
      } finally {
        setLoading(false);
      }
    };
  
    useEffect(() => {
      refreshGuilds();
    }, [user]);
  
    return (
      <form onSubmit={(e) => {
        e.preventDefault();
        refreshGuilds();
      }}>
        <Button variant="outline" disabled={loading}>
          {loading ? <Loader2 className="mr-2 h-5 w-5 animate-spin" /> : <RefreshCw className="mr-2 h-5 w-5" />}
          <span className="text-base">Refresh</span>
        </Button>
      </form>
    );
  }
Don't forget to import useEffect hook