๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

FrontEnd/React

[React] ๋ชจ๋“œ ๊ฐ’์— ๋”ฐ๋ฅธ ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ (+๋ฆฌํŒฉํ† ๋ง)

๐Ÿ“Œ ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋งŒ๋“ค๊ธฐ 

์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋งŒ๋“ค์—ˆ๋˜ ๋ฐฉ๋ฒ• ๋ฐ ๋ฆฌํŒฉํ† ๋ง ํ›„๊ธฐ์— ๋Œ€ํ•ด์„œ ๊ธ€์„ ์จ๋ณด๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

 

์šฐ์„  ์ œ๊ฐ€ ํ•˜๊ณ  ์‹ถ์€ ๊ฑฐ๋Š” ๊ฐ ๋ฒ„ํŠผ์— ๊ด€ํ•œ ์†์„ฑ์„ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์—‡ ๋†“๊ณ  , ๊ทธ ์ปดํฌ๋„ŒํŠธ์—์„œ mode๊ฐ’์„ ํ† ๋Œ€๋กœ 

์›ํ•˜๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ฐ›๋Š” ๊ฒƒ์„ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. 

 

์ค€๋น„๋ฌผ 

  • React
  • styled-components
  • ์›ํ•˜๋Š” ์†Œ์…œ ๋กœ๊ทธ์ธ ์•„์ด์ฝ˜ 

 

์ฒ˜์Œ์— ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ 

import styled from "styled-components";
import { SocialIcons } from "src/assets/images/SocialIcons";
import { ButtonHTMLAttributes } from "react";

interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
  children: React.ReactNode;
  width?: number;
  height?: number;
  bgColor?: string;
  color?: string;
  borderRadius?: number;
  mode?: "kakao" | "google" | "naver" | "github" | "facebook";
  onClick?: () => void;
}

const SocialLoginButton = ({ mode, children, ...props }: Props) => {
  if (mode === "kakao") {
    return (
      <Button {...props} bgColor="#F8DF02" onClick={props.onClick}>
        <img src={SocialIcons.kakaoLogo} alt="kakaoLogoIcons" />
        <span>{children}</span>
      </Button>
    );
  }
  if (mode === "naver") {
    return (
      <Button
        {...props}
        bgColor="#39B35D"
        color="white"
        onClick={props.onClick}
      >
        <img src={SocialIcons.naverLogo} alt="kakaoLogoIcons" />
        <span>{children}</span>
      </Button>
    );
  }
  if (mode === "google") {
    return (
      <Button {...props} bgColor="#EAEDEF" onClick={props.onClick}>
        <img src={SocialIcons.googleLogo} alt="kakaoLogoIcons" />
        <span>{children}</span>
      </Button>
    );
  }
  if (mode === "facebook") {
    return (
      <Button
        {...props}
        bgColor="#4267B2"
        color="white"
        onClick={props.onClick}
      >
        <img src={SocialIcons.facebookLogo} alt="kakaoLogoIcons" />
        <span>{children}</span>
      </Button>
    );
  }
  if (mode === "github") {
    return (
      <Button
        {...props}
        bgColor="#222222"
        color="white"
        onClick={props.onClick}
      >
        <img src={SocialIcons.githubLogo} alt="kakaoLogoIcons" />
        <span>{children}</span>
      </Button>
    );
  }
  return (
    <Button {...props} bgColor="black" color="white">
      <span>{children ?? "Login"}</span>
    </Button>
  );
};

export default SocialLoginButton;

const Button = styled.button<Props>`
  margin: 0.3rem 0rem;
  position: relative;
  width: ${(props) => props.width ?? "20"}rem;
  height: ${(props) => props.height ?? "3"}rem;
  background-color: ${(props) => props.bgColor ?? "skyblue"};
  color: ${(props) => props.color ?? "black"};
  display: flex;
  justify-content: center;
  align-items: center;
  border: none;
  cursor: pointer;
  font-weight: bold;
  border-radius: ${(props) => props.borderRadius ?? 0}rem;
  & > img {
    padding-right: 0.5rem;
    width: 20px;
    height: 20px;
    left: 0;
    margin-left: 20px;
    position: absolute;
  }
  & > span {
    padding-left: 0.5rem;
  }
`;

์ฒ˜์Œ์— ์ œ๊ฐ€ ๊ฐ ๋ชจ๋“œ ๊ฐ’์— ๋”ฐ๋ผ์„œ ์ง  ์ฝ”๋“œ ์ž…๋‹ˆ๋‹ค. 

๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…์„ ํ•˜์ž๋ฉด , ๊ฐ๊ฐ css ์†์„ฑ๊ฐ’์„ ๋ฐ›์•„์„œ ์Šคํƒ€์ผ๋“œ ์ปดํฌ๋„ŒํŠธ props๋กœ ๋„˜๊ฒจ์ค˜์„œ ์ปค์Šคํ…€์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๊ณ  , 

๊ฐ๊ฐ ๋ชจ๋“œ ๊ฐ’์„ ๋ฐ›์•„์„œ ๊ทธ ๋ชจ๋“œ์— ํ•ด๋‹นํ•˜๋Š” ๋ฒ„ํŠผ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌํ„ด๋  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ์ฝ”๋“œ๋ฅผ ๋ณด๋‹ค ๋ณด๋ฉด , ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„์ด ๋งŽ๊ณ  ๋ฉ”์ธ ๋กœ์ง ์ฝ”๋“œ๊ฐ€ ์ž˜ ์ฝํ˜€์ง€์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฉด ์ด๊ฑธ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•ด์•ผ ํ•˜๋‚˜์˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ค‘๋ณต๋˜์ง€ ์•Š๊ณ  , ๊ฐ๊ฐ ๋ชจ๋“œ ๊ฐ’์„ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์„๊นŒ์š” ? 

 

์ €๋Š” ์œ ํŠœ๋ธŒ์—์„œ ๋ฐค๋งˆ๋‹ค ๋ผ์ด๋ธŒ ์ฝ”๋”ฉ์„ ํ•˜์‹œ๋Š” ๋ฒจ๋กœํผํŠธ ๊น€๋ฏผ์ค€๋‹˜ ๋ผ์ด๋ธŒ ๋ฐฉ์†ก์„ ๋ณด๋‹ค ์˜๊ฐ์„ ๋ฐ›์•„์„œ ๋ฆฌํŒฉํ† ๋ง์„ ํ•ด๋ดค๋Š”๋ฐ์š” . 

๊ฐ๊ฐ mode๊ฐ’์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’๋“ค์„ ๋ฏธ๋ฆฌ ๊ฐ์ฒด๋กœ ์ง€์ •ํ•ด ๋†“๊ณ  , ๊ทธ ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์ž…๋‹ˆ๋‹ค.. ! ! 

 

๋ฆฌํŒฉํ† ๋ง ๊ฒฐ๊ณผ๋ฅผ ๋ด๋ณผ๊ฐ€์š” ? 

 

import styled from "styled-components";
import { SocialIcons } from "src/assets/images/SocialIcons";
import { ButtonHTMLAttributes } from "react";

interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
  children: React.ReactNode;
  width?: number;
  height?: number;
  bgColor?: string;
  color?: string;
  borderRadius?: number;
  mode: "kakao" | "google" | "naver" | "github" | "facebook";
  onClick?: () => void;
}

interface SocialType {
  bgColor: string;
  color: string;
  logoIcon: string;
}

interface SocialIconsOptionType {
  [key: string]: SocialType;
}

const SocialLoginOption: SocialIconsOptionType = {
  kakao: {
    bgColor: "#F8DF02",
    color: "black",
    logoIcon: SocialIcons.kakaoLogo,
  },
  naver: {
    bgColor: "#39B35D",
    color: "white",
    logoIcon: SocialIcons.naverLogo,
  },
  google: {
    bgColor: "#EAEDEF",
    color: "black",
    logoIcon: SocialIcons.googleLogo,
  },
  facebook: {
    bgColor: "#4267B2",
    color: "white",
    logoIcon: SocialIcons.facebookLogo,
  },
  github: {
    bgColor: "#222222",
    color: "white",
    logoIcon: SocialIcons.githubLogo,
  },
};

const SocialLoginButton = ({ mode, children, ...props }: Props) => {
  const { bgColor, color, logoIcon } = SocialLoginOption[mode];
  return (
    <Button
      {...props}
      bgColor={bgColor}
      color={color}
      onClick={props.onClick}
      mode={mode}
    >
      <img src={logoIcon} alt="kakaoLogoIcons" />
      <span>{children}</span>
    </Button>
  );
};

export default SocialLoginButton;

const Button = styled.button<Props>`
  margin: 0.3rem 0rem;
  position: relative;
  width: ${(props) => props.width ?? "20"}rem;
  height: ${(props) => props.height ?? "3"}rem;
  background-color: ${(props) => props.bgColor ?? "skyblue"};
  color: ${(props) => props.color ?? "black"};
  display: flex;
  justify-content: center;
  align-items: center;
  border: none;
  cursor: pointer;
  font-weight: bold;
  border-radius: ${(props) => props.borderRadius ?? 0}rem;
  & > img {
    padding-right: 0.5rem;
    width: 20px;
    height: 20px;
    left: 0;
    margin-left: 20px;
    position: absolute;
  }
  & > span {
    padding-left: 0.5rem;
  }
`;

๊ธฐ๋ณธ ๋ฒ„ํŠผ์„ ์—†์• ๊ณ  ๊ฐ ๋ชจ๋“œ๊ฐ’์„ ํ•„์ˆ˜ ์†์„ฑ์œผ๋กœ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋กœ์ง์„ ๋ณ€๊ฒฝ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ๊ฐ๊ฐ ์˜ต์…˜๋“ค์„ ๊ฐ์ฒด๋กœ ๋บ๊ธฐ ๋•Œ๋ฌธ์— , ์ฃผ์š” ๋ฉ”์ธ๋กœ์ง ๋ถ€๋ถ„์ด ์ง€์ €๋ถ„ ํ•˜์ง€ ์•Š๊ณ  ๊น”๋”ํ•˜๊ฒŒ ์ ์šฉ๋œ ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. 

 

๐Ÿ“ํ›„๊ธฐ

์ง€์ €๋ถ„ ํ–ˆ๋˜ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊ฐ€๋…์„ฑ ์ข‹๊ณ  ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌ๋˜์–ด์„œ ๊ธฐ๋ถ„์ด ์ข‹์•˜๋˜ ๋ฆฌํŒฉํ† ๋ง ์ž…๋‹ˆ๋‹ค ~ !! 

๋˜ํ•œ , ์ฃผ๋ณ€ ๋™๋ฃŒ ๊ฐœ๋ฐœ์ž๋“ค ํ•œํ…Œ ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์คฌ์„ ๊ฒฝ์šฐ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•˜๊ณ  ๊น”๋”ํ•˜๋‹ค๋Š” ๋Š๋‚Œ์„ ๋ฐ›๋Š”๋‹ค๋Š” ํ‰์„ ๋“ค์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค !!