3 분 소요


경로와 매칭되었을 때 특정 스타일이나 클래스를 적용할 수 있는 기능을 사용하고 싶은 경우는 [NavLink↗️]를 사용하도록 하자!


1. Styled Components로 tap 활성화 구현하기

어떤 탭이 클릭되었는지 아래처럼 style-components의 조건부 스타일링을 적용하여 구현해보자!


1.1 적용 전 초기 코드

import styled from "styled-components";

function Tabs() {
  const tabItems = ["토토로", "키키", "포뇨", "치히로", "소피", "가오나시"];

  return (
    <TabsList>
      <TabsTitle>누구에게 보내실 건가요?</TabsTitle>
      {tabItems.map((item, index) => {
        return <TabsItem key={index}>{item}</TabsItem>;
      })}
    </TabsList>
  );
}

const TabsList = styled.ul`
  background-color: #ffffff;
  width: 390px;
  border-radius: 13px;
  padding: 45px;
  margin-right: 30px;
`;

const TabsTitle = styled.h1`
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 30px;
`;
const TabsItem = styled.li`
  border-radius: 8px;
  border: 2px solid #bababa;
  height: 65px;
  margin-bottom: 15px;
  font-size: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
`;

export default Tabs;


1.2 state 생성

useState 훅을 사용하여 현재 활성화된 탭을 관리하자.

const [activeTab, setActiveTab] = useState("토토로");


1.3 tap 렌더링

  • tabItems 배열을 순회하며 각 탭을 렌더링하자. 각 탭이 클릭되면 setActiveTab을 호출하여 상태를 업데이트한다.
  • 그리고 props로 조건부 스타일을 주자. 스타일 컴포넌트 특성상 카멜 케이스 사용시 $를 앞에 붙여줘야한다!
<TabsList>
  <TabsTitle>누구에게 보내실 건가요?</TabsTitle>
  {tabItems.map((item, index) => (
    <TabsItem
      key={index}
      $isActive={item === activeTab}
      onClick={() => setActiveTab(item)}
    >
      {item}
    </TabsItem>
  ))}
</TabsList>


1.3 조건부 스타일링

props.$isActive를 사용하여 활성화된 탭과 비활성화된 탭에 대해 서로 다른 스타일을 적용하자

import styled, { css } from "styled-components"; // import(retrun에 css치고 tap누르면 자동 import)
const TabsItem = styled.li`
  border-radius: 8px;
  border: 2px solid #bababa;
  height: 65px;
  margin-bottom: 15px;
  font-size: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;

  ${(props) =>
    props.$isActive
      ? css`
          border: 2px solid black;
          font-weight: bold;
        `
      : css`
          border: 2px solid #bababa;
          font-weight: normal;
        `}
`;


1.4 전체코드

import { useState } from "react";
import styled, { css } from "styled-components";

const Tabs = () => {
  const [activeTab, setActiveTab] = useState("토토로");

  const tabItems = ["토토로", "키키", "포뇨", "치히로"];

  return (
    <TabsList>
      <TabsTitle>누구에게 보내실 건가요?</TabsTitle>
      {tabItems.map((item, index) => (
        <TabsItem
          key={index}
          $isActive={item === activeTab}
          onClick={() => setActiveTab(item)}
        >
          {item}
        </TabsItem>
      ))}
    </TabsList>
  );
};

const TabsList = styled.ul`
  background-color: #ffffff;
  width: 390px;
  border-radius: 13px;
  padding: 45px;
  margin-right: 30px;
`;

const TabsTitle = styled.h1`
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 30px;
`;

const TabsItem = styled.li`
  border-radius: 8px;
  border: 2px solid #bababa;
  height: 65px;
  margin-bottom: 15px;
  font-size: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;

  ${(props) =>
    props.$isActive
      ? css`
          border: 2px solid black;
          font-weight: bold;
        `
      : css`
          border: 2px solid #bababa;
          font-weight: normal;
        `}
`;

export default Tabs;



2. Context API 사용하기

2.1 TabsContext 생성

로컬스토리지와 세션 스토리지의 차이는 [여기↗️] 서 확인하자!

로컬스토리지와 세션 스토리지를 사용해서 새로고침 시에도 데이터가 유지되도록 해보자!

2.1.1 [방법1] sessionStorage 사용

import { createContext, useContext, useState, useEffect } from "react";

const TabsContext = createContext();

export function TabsProvider({ children }) {
  // sessionStorage에서 초기 상태를 가져오거나 "토토로"로 초기화
  const [activeTab, setActiveTab] = useState(
    () => sessionStorage.getItem("activeTab") || "토토로"
  );

  useEffect(() => {
    // activeTab이 변경될 때마다 sessionStorage에 저장
    sessionStorage.setItem("activeTab", activeTab);
  }, [activeTab]);

  return (
    <TabsContext.Provider value={{ activeTab, setActiveTab }}>
      {children}
    </TabsContext.Provider>
  );
}

export function useTabs() {
  return useContext(TabsContext);
}


2.2.2 [방법2] localStorage 사용

import { createContext, useContext, useState, useEffect } from "react";

const TabsContext = createContext();

export function TabsProvider({ children }) {
  // localStorage에서 초기 상태를 가져오거나 "토토로"로 초기화
  const [activeTab, setActiveTab] = useState(
    () => localStorage.getItem("activeTab") || "토토로"
  );

  useEffect(() => {
    // activeTab이 변경될 때마다 localStorage에 저장
    localStorage.setItem("activeTab", activeTab);
  }, [activeTab]);

  return (
    <TabsContext.Provider value={{ activeTab, setActiveTab }}>
      {children}
    </TabsContext.Provider>
  );
}

export function useTabs() {
  return useContext(TabsContext);
}


2.3 Context Provider로 감싸기

import Tabs from "components/ContextPractice/Tabs";
import { TabsProvider } from "../context/TabsContext"; // Import the provider

const HomePage = () => {
  return (
    <div>
      <TabsProvider>
        <Tabs />
      </TabsProvider>
    </div>
  );
};

export default HomePage;


2.4 Tabs 컴포넌트에서 Context 사용하기

import styled, { css } from "styled-components";
import { useTabs } from "../../context/TabsContext";

function Tabs() {
  const tabItems = ["토토로", "키키", "포뇨", "치히로", "소피", "가오나시"];
  const { activeTab, setActiveTab } = useTabs();

  return (
    <TabsList>
      <TabsTitle>누구에게 보내실 건가요?</TabsTitle>
      {tabItems.map((item, index) => (
        <TabsItem
          onClick={() => setActiveTab(item)}
          $isActive={item === activeTab}
          key={index}
        >
          {item}
        </TabsItem>
      ))}
    </TabsList>
  );
}

const TabsList = styled.ul`
  background-color: #ffffff;
  width: 390px;
  border-radius: 13px;
  padding: 45px;
  margin-right: 30px;
`;

const TabsTitle = styled.h1`
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 30px;
`;

const TabsItem = styled.li`
  border-radius: 8px;
  border: 2px solid #bababa;
  height: 65px;
  margin-bottom: 15px;
  font-size: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;

  ${(props) =>
    props.$isActive
      ? css`
          border: 2px solid black;
          font-weight: bold;
        `
      : css`
          border: 2px solid #bababa;
          font-weight: normal;
        `}
`;

export default Tabs;


아래와 같이 구현할 수도 있다!

font-weight: ${(props) => (props.$isActive ? 'bold' : '')};
border: ${(props) => (props.$isActive ? '2px solid black' : '')};



3. 부족한점😫


카테고리:

업데이트:

댓글남기기