24.09.28

๊ฐ•์—ฐ์ฃผยท2024๋…„ 9์›” 28์ผ

๐Ÿ“š TIL

๋ชฉ๋ก ๋ณด๊ธฐ
46/186

๐Ÿฃ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… 1

FetchUserData.tsx (1)

๐Ÿšจ ์ค‘๋ณต ํŽ˜์นญ ๋ฌธ์ œ (FetchUserData.tsx ์‹คํšจ์„ฑ X)
๐Ÿšจ provider๋กœ children์„ ๊ฐ์‹ธ์ž
๐Ÿšจ useContext vs ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ํ”„๋กญ์Šค ์ „๋‹ฌ

๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ๋งค๋ฒˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์žˆ์—ˆ๊ณ ,
FetchUserData.tsx๋Š” ์• ์ดˆ์— ์กด์žฌ ์ด์œ ๋„ ์—†์—ˆ์Œ์„ ๊นจ๋‹ฌ์•˜์–ด์š”...

โญย ์œ„ ๋ฌธ์ œ๋ฅผ ๊ฐœ์„ ํ•œ provider ๋ฐฉ์‹

๐Ÿ–ฅ๏ธย FetchUserDataProvider.tsx

'use client';

import { supabase } from '@/supabase/client';
import React, { useEffect } from 'react';
import useUserStore from '@/stores/user.store';

export const FetchUserDataProvider = ({ children }: { children: React.ReactNode }) => {
  const { setUserId, setNickname, setLevelName, setAttendance, setEmail } = useUserStore((state) => state);

  useEffect(() => {
    const fetchUserData = async () => {
      const { data: authData, error: authError } = await supabase.auth.getUser();
      if (authError) {
        console.error('Authentication user data fetch error:', authError);
        return;
      }

      const user = authData?.user;
      if (user) {
        // console.log('Fetched user ID:', user.id); // ๋””๋ฒ„๊น… ์ฝ”๋“œ ์ถ”๊ฐ€
        setUserId(user.id);
        setEmail(user.email ?? null);

        // TODO: supabase users ํ•œ ๋ฒˆ๋งŒ ๊ฐ€์ ธ์™€๋„ ๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ์˜ˆ?
        // TODO: ๋งž์Šต๋‹ˆ๋‹ค...

        const { data: nicknameData, error: nicknameError } = await supabase
          .from('users')
          .select('nickname')
          .eq('id', user.id)
          .single();
        if (nicknameError) {
          console.error('๋‹‰๋„ค์ž„ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', nicknameError);
        } else {
          setNickname(nicknameData.nickname ?? ''); // ์ „์—ญ ์ƒํƒœ์— ๋‹‰๋„ค์ž„ ์„ค์ •
        }

        const { data: levelData, error: levelError } = await supabase
          .from('users')
          .select('level_id')
          .eq('id', user.id)
          .single();
        if (levelError) {
          console.error('๋ ˆ๋ฒจ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', levelError);
        } else if (levelData.level_id) {
          const { data: levelNameData, error: levelNameError } = await supabase
            .from('level')
            .select('name')
            .eq('id', levelData.level_id)
            .single();
          if (levelNameError) {
            console.error('๋ ˆ๋ฒจ ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', levelNameError);
          } else {
            setLevelName(levelNameData.name); // ์ „์—ญ ์ƒํƒœ์— ๋ ˆ๋ฒจ ์ด๋ฆ„ ์„ค์ •
          }
        }

        // users ํ…Œ์ด๋ธ”์—์„œ ์ถœ์„ ํšŸ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ
        const { data: attendanceData, error: attendanceError } = await supabase
          .from('users')
          .select('attendance')
          .eq('id', user.id)
          .single();
        if (attendanceError) {
          console.error('์ถœ์„ ํšŸ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', attendanceError);
        } else {
          setAttendance(attendanceData.attendance);
        }
      }
    };

    fetchUserData();
  }, [setNickname, setLevelName, setUserId, setAttendance, setEmail]);

  return <>{children}</>;
};

export default FetchUserDataProvider;

๋ฃจํŠธ ๋ ˆ์ด์•„์›ƒ์—์„œ children์„ provider๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด,
๊ฐ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ์ƒํƒœ๊ด€๋ฆฌ๋ž‘ ๋ Œ๋”๋ง๋งŒ ํ•˜๋ฉด ๋œ๋‹ค..!
๋ฆฌํŒฉํ† ๋ง ํ˜น์€ ์ฝ”๋“œ ๋ผ์ธ ์ค„์ด๋ฉด์„œ ๋– ๋Š” ํ˜ธ๋“ค๊ฐ‘์ด
์‚ฌ์‹ค ๋งˆ์Œ์œผ๋กœ ์™€๋‹ฟ์ง€ ์•Š์„ ๋•Œ๊ฐ€ ๋งŽ์•˜๋Š”๋ฐ, ์ด๊ฑด ์ง„์งœ ์ข€ ์•„๋ฆ„๋‹ต๋‹ค.
์™œ๋ƒ๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๋ชจ๋ฅด๋Š” ๋‚ด ๋ˆˆ์—๋„ ์ปดํฌ๋„ŒํŠธ๋งˆ๋‹ค ๋ฐ˜๋ณต๋˜๋Š” fetching์€
์ •๋ง,, ๊ตฌ๋ ธ๊ฑฐ๋“ ์šฉ...ใ…Ž

GrowthSummary๋Š” ์œ ์ € ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋“ค ์ค‘ ํ•˜๋‚˜๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ์ „์—ญ์ƒํƒœ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์ง์ ‘ ๋ Œ๋”๋งํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. provider ๋•๋ถ„์— ๋ฐ์ดํ„ฐ fetching์„ ์ˆ˜ํ–‰ํ•  ํ•„์š”๊ฐ€ ์—†์–ด์กŒ๋‹ค.

๐ŸŒ€ ์ˆ˜์ • ์ „

'use client';
import { supabase } from '@/supabase/client';
import React from 'react';
import { useEffect } from 'react';
import useUserStore from '@/stores/user.store';

export const FetchUserData = () => {
  const { setUserId, setNickname, setLevelName, setAttendance, setEmail } = useUserStore((state) => state);

  useEffect(() => {
    const fetchUserData = async () => {
      const { data: authData, error: authError } = await supabase.auth.getUser();
      if (authError) {
        console.error('Authentication user data fetch error:', authError);
        return;
      }
      const user = authData?.user;
      if (user) {
        setUserId(user.id);
        setEmail(user.email ?? null);

        const { data: nicknameData, error: nicknameError } = await supabase
          .from('users')
          .select('nickname')
          .eq('id', user.id)
          .single();
        if (nicknameError) {
          console.error('๋‹‰๋„ค์ž„ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', nicknameError);
        } else {
          setNickname(nicknameData.nickname ?? '');
        }

        const { data: levelData, error: levelError } = await supabase
          .from('users')
          .select('level_id')
          .eq('id', user.id)
          .single();

        if (levelError) {
          console.error('๋ ˆ๋ฒจ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', levelError);
        } else if (levelData.level_id) {
          const { data: levelNameData, error: levelNameError } = await supabase
            .from('level')
            .select('name')
            .eq('id', levelData.level_id)
            .single();

          if (levelNameError) {
            console.error('๋ ˆ๋ฒจ ์ด๋ฆ„ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', levelNameError);
          } else {
            setLevelName(levelNameData.name);
          }
        }

        const { data: attendanceData, error: attendanceError } = await supabase
          .from('users')
          .select('attendance')
          .eq('id', user.id)
          .single();

        if (attendanceError) {
          console.error('์ถœ์„ ํšŸ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ:', attendanceError);
        } else {
          setAttendance(attendanceData.attendance);
        }
      }
    };

    fetchUserData();
  }, [setNickname, setLevelName, setUserId, setAttendance, setEmail]);
  return null;
};

๐Ÿ–ฅ๏ธย GrowthSummary.tsx

'use client';

import React, { useEffect, useState } from 'react';
// import FetchUserData from '@/lib/utils/FetchUserData';
import FetchMembershipDays from '@/lib/utils/FetchMembershipDays';
import useUserStore from '@/stores/user.store';
import ProfileStages from '../molecules/ProfileStages';
import { supabase } from '@/supabase/client';
import AttendanceCheck from '@/lib/utils/AttendanceCheck';

const GrowthSummary = () => {
  const { nickname, levelName, membershipDays, userId, setLevelId, updatedLevelId } = useUserStore((state) => state);

  useEffect(() => {
    const fetchUserLevelId = async () => {
      if (userId) {
        const { data: user, error } = await supabase.from('users').select('level_id').eq('id', userId).single();

        if (!error && user) {
          setLevelId(user.level_id); // Global ์ƒํƒœ ์—…๋ฐ์ดํŠธ
        } else {
          console.error('์‚ฌ์šฉ์ž ๋ ˆ๋ฒจID ๊ฐ€์ ธ์˜ค๊ธฐ ์‹คํŒจ: ', error);
        }
      }
    };
    fetchUserLevelId();
  }, [userId, setLevelId]);

  return (
    <>
      {/* <FetchUserData /> */}
      <AttendanceCheck />
      <FetchMembershipDays />

      <div
        className="flex flex-row w-[98rem] h-[14.8rem] sm:w-[38rem] sm:h-[9.6rem] pt-[3.2rem] pb-[2rem] sm:pt-[1.2rem] sm:pb-[1.2rem] bg-white
      rounded-tr-[2rem] rounded-tl-[2rem]"
      >
        <div className="ml-[3.2rem] sm:ml-[2rem] w-[9.6rem] h-[9.6rem] sm:w-[7.2rem] sm:h-[7.2rem]">
          {updatedLevelId && <ProfileStages size={96} />}
        </div>{' '}
        {/* updatedLevelId ์‚ฌ์šฉ */}
        <div className="items-center ml-[1.6rem]">
          <span className="font-semibold text-[2.6rem] sm:text-[1.8rem] text-[#008A02]">{levelName}</span>
          <span className="font-semibold text-[2.6rem] sm:text-[1.8rem] ml-[1.6rem] sm:ml-[0.8rem]">
            {nickname} ๋‹˜์˜ ์ •์›
          </span>

          <div className="font-semibold text-[1.8rem] sm:text-[1.3rem] text-[#727272]">
            <p>ํ”Œ๋žœํŠธ๋ฆฌ์™€ ํ•จ๊ป˜ {membershipDays}์ผ์งธ,</p>
            <div className="flex justify-between">์—ด์‹ฌํžˆ ๋‚˜๋ฌด๋ฅผ ํ‚ค์šฐ๊ณ  ๊ณ„์‹œ๋„ค์š”!</div>
          </div>
        </div>
      </div>
    </>
  );
};

export default GrowthSummary;

FetchUserData.tsx (2)

๐Ÿšจ useEffect ๋‚ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•˜๋Š” ๊ฒƒ์€ ์•ˆํ‹ฐ ํŒจํ„ด

๐Ÿšจ ํ•˜๋‚˜์˜ ํ›…์—์„œ ๋„ˆ๋ฌด ๋งŽ์€ ์ž‘์—…์ด ์ด๋ฃจ์–ด์ง€๊ณ  ์žˆ๋‹ค
๐Ÿšจ ๋กœ์ปฌ ์ „์—ญ์ƒํƒœ๊ด€๋ฆฌ์™€ ๋ฐ์ดํ„ฐ ํŽ˜์นญ๊ณผ ์—ฐ๋™ ์ƒํƒœ๊ด€๋ฆฌ๋ฅผ ๋ถ„๋ฆฌํ•ด์•ผ ํšจ์œจ์ 

  • ๋ชจ๋‹ฌ ์‚ฌ์šฉ์—๋งŒ zustand๋ฅผ,
    ๊ทธ ์™ธ์—๋Š” TanstackQuery์‚ฌ์šฉ
  • ์ปค์Šคํ…€ํ›… ์‚ฌ์šฉ

FetchUserData.tsx (3)

๐Ÿšจ userId๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ๋‚˜๋จธ์ง€ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ enbled ์˜ต์…˜ ์‚ฌ์šฉ
๐Ÿšจ ์ „์ฒด ์ •๋ณด ๋ Œ๋”๋ง ์ปดํฌ๋„ŒํŠธ & ๊ฐœ๋ณ„ ์ •๋ณด ๋ Œ๋”๋ง ์ปดํฌ๋„ŒํŠธ

  • ์ปค์Šคํ…€ ํ›… ๊ตฌ๋ณ„ํ•ด์„œ ์‚ฌ์šฉ
  • children์„ ๊ฐ์‹ธ๋Š” ๋ฐฉ๋ฒ•

๊ธฐ๋Šฅ : ๋ฐ์ดํ„ฐ ํŽ˜์นญ, ๋ฐ์ดํ„ฐ ๋ Œ๋”๋ง, (์ž๋™) ์—…๋ฐ์ดํŠธ, ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง
๋ฌธ์ œ : ์ค‘๋ณต ํŽ˜์นญ, ๊ฐ€๋…์„ฑ ์ €ํ•˜, ๋‹จ์ผ ํ›…์˜ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ธฐ๋Šฅ, ๋‚ฎ์€ ์ดํ•ด๋„
๋ชฉ์  : ๋ฐ์ดํ„ฐ ํŽ˜์นญ ๋กœ์ง ๊ฐ„๊ฒฐํ™”, ์ „๋ฐ˜์ ์ธ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ


??, ๋„ ๋ณ‘ํ•ฉ ์—ฐ์‚ฐ์ž (Nullish Coalescing Operator)

์™ผ์ชฝ์˜ ๊ฐ’์ด null ๋˜๋Š” undefined์ผ ๊ฒฝ์šฐ, ์˜ค๋ฅธ์ชฝ์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜.

?. (Optional Chaining Operator)

?.๋Š” ์˜ต์…”๋„ ์ฒด์ด๋‹ ์—ฐ์‚ฐ์ž๋กœ, user๊ฐ€ null ๋˜๋Š” undefined์ธ ๊ฒฝ์šฐ,
์—๋Ÿฌ ์—†์ด undefined๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
์ฆ‰, user๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ์—๋Š” user.id๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ ,
๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด undefined๋ฅผ ๋ฐ˜ํ™˜.


๐Ÿ–ฅ๏ธ const userId = user?.id ?? null;

user?.id์˜ ๊ฒฐ๊ณผ๊ฐ€ null ๋˜๋Š” undefined์ผ ๊ฒฝ์šฐ,
?? ์—ฐ์‚ฐ์ž ์šฐ์ธก์˜ ๊ฐ’ ์ฆ‰, null์„ userId์— ํ• ๋‹นํ•œ๋‹ค.

๋งŒ์•ฝ user?.id๊ฐ€ 0, false, ๋นˆ ๋ฌธ์ž์—ด("") ๊ฐ™์€ "falsy" ๊ฐ’์ด์–ด๋„,
๊ทธ ๊ฐ’ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜
๋˜๋Š”๋ฐ, ์ด๋Š” ๋…ผ๋ฆฌ์  OR (||)์™€์˜ ์ฐจ์ด์ ์ด๋‹ค.
|| ์—ฐ์‚ฐ์ž๋Š” falsyํ•œ ๊ฐ’์„ ๋งŒ๋‚˜๋ฉด ์šฐ์ธก ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐ˜๋ฉด,
??๋Š” null๊ณผ undefined๋งŒ ์ฒ˜๋ฆฌํ•œ๋‹ค.

โžก๏ธ user?.id๊ฐ€ null ๋˜๋Š” undefined์ด๋ฉด null์„ ๋ฐ˜ํ™˜ํ•˜๊ณ ,
๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด user?.id์˜ ๊ฐ’์„ userId์— ํ• ๋‹นํ•˜๋Š” ์ฝ”๋“œ.

profile
์•„๋ฌดํŠผ, ๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€