Next.js Discord

Discord Forum

Types

Answered
Blue Picardy Spaniel posted this in #help-forum
Open in Discord
Blue Picardy SpanielOP
export const GuildProvider: React.FC<{ initialGuilds: UserGuild[] | null, children: ReactNode }> = ({ initialGuilds, children }) => {
  const router = useRouter();

  const [guilds, setGuilds] = useState<UserGuild[] | null>(initialGuilds);
  if(!initialGuilds) router.push("/api/auth"); // REDIRECT IS HERE

  const updateGuildSetting = (guildID: string, settingKey: string, value: SettingValue) => {
    setGuilds(prevGuilds => {
      if(!prevGuilds) return null;

      const newSettings = prevGuilds.map(guild =>
        guild.id === guildID
          ? { ...guild, settings: { ...guild.settings, [settingKey]: value } } as UserGuild
          : guild
      );

      setGuildSetting(guildID, settingKey, value);
      return newSettings;
    });
  };

  return (
    <GuildContext.Provider value={{ guilds, updateGuildSetting }}>
      {children}
    </GuildContext.Provider>
  );
};

Currently, guilds is typed as UserGuild[] | null, however since I'm redirecting the user if they have no initialGuilds, guilds type is technically UserGuild[]. How do I reflect this to TypeScript when I pass the guilds variable to my provider?
Answered by B33fb0n3
Of course not inside the clientside file (provider). There, where you use the component. Like:
const guilds = await getUserGuilds();

if(!guilds)
  redirect("/");

return <div>
  <GuildProvider initialGuilds={guilds}>
    <p>Some other components</p>
  </GuildProvider>
</div>
View full answer

11 Replies

@B33fb0n3 return after redirect. So like: tsx if(!initialGuilds) { router.push("/api/auth"); // REDIRECT IS HERE return; }
Blue Picardy SpanielOP
this works for initialGuilds however since im passing guilds to the provider, guilds still shows as possibly null
@Blue Picardy Spaniel this works for initialGuilds however since im passing guilds to the provider, `guilds` still shows as possibly null
oh my bad. Replace initialGuilds with guilds (your useState) and your context can only be set. I couldn't directly see the type of your context, but I guess that should currently be UserGild[] | null & the function to update
@B33fb0n3 oh my bad. Replace initialGuilds with guilds (your useState) and your context can only be set. I couldn't directly see the type of your context, but I guess that should currently be UserGild[] | null & the function to update
Blue Picardy SpanielOP
this is gonna sound really picky but one issue with this is that when i log out, i don't get redirected. i have to refresh to get redirected, but when i do initialGuilds instead of guilds, it redirects instantly. im not sure why that is
@B33fb0n3 can you redirect serverside instead of clientside?
Blue Picardy SpanielOP
no since this is in a client file
"use client";

import type { ReactNode } from "react";
import React, { createContext, useState, useContext } from "react";
import { useRouter } from "next/navigation";
import type { UserGuild } from "@/types/guilds";
import { setGuildSetting } from "@/db/access/guilds";
import type { SettingValue } from "@/types/settings";

interface GuildContextType {
  guilds: UserGuild[] | null;
  updateGuildSetting: (guildId: string, settingKey: string, value: SettingValue) => void;
}

const GuildContext = createContext<GuildContextType | undefined>(undefined);

export const GuildProvider: React.FC<{ initialGuilds: UserGuild[] | null, children: ReactNode }> = ({ initialGuilds, children }) => {
  const router = useRouter();

  const [guilds, setGuilds] = useState<UserGuild[] | null>(initialGuilds);
  if(!initialGuilds) {
    router.push("/api/auth");
    return;
  }

  const updateGuildSetting = (guildID: string, settingKey: string, value: SettingValue) => {
    setGuilds(prevGuilds => {
      if(!prevGuilds) return null;

      const newSettings = prevGuilds.map(guild =>
        guild.id === guildID
          ? { ...guild, settings: { ...guild.settings, [settingKey]: value } } as UserGuild
          : guild
      );

      setGuildSetting(guildID, settingKey, value);
      return newSettings;
    });
  };

  return (
    <GuildContext.Provider value={{ guilds, updateGuildSetting }}>
      {children}
    </GuildContext.Provider>
  );
};

export const useGuilds = (): GuildContextType => {
  const context = useContext(GuildContext);
  if(context === undefined) throw new Error("useGuilds must be used within a GuildProvider");

  return context;
};
@Blue Picardy Spaniel no since this is in a client file
Of course not inside the clientside file (provider). There, where you use the component. Like:
const guilds = await getUserGuilds();

if(!guilds)
  redirect("/");

return <div>
  <GuildProvider initialGuilds={guilds}>
    <p>Some other components</p>
  </GuildProvider>
</div>
Answer
feel free to change the solution to the correct message if I missed the correct one