Weekly TIL - Day 14

2025. 4. 28. 09:21·Weekly TIL

⭐️ Today's summary

오늘은 전역 상태를 간단하게 관리할 수 있는 경량 상태관리 라이브러리인 zustand를 배웠다.

 

이를 통해 간단한 API로 전역 상태를 관리할 수 있고, 사용법이 직관적이며, Provider, 액션 타입 등 복잡한

구조도 불필요하다.

 

처음 접하는거기에 사용법을 정리해 보겠다.

⭐️ Problem

zustand의 기본 문법과 사용법에 익숙하지 않아 코드로 정리해보겠다.

 

⭐️ Try

[ App.jsx ]

** App.jsx **

import './App.css';
import { styled } from 'styled-components';
import CounterDisplay from './components/zustand/CounterDisplay';
import CounterControls from './components/zustand/CounterControls';
import TodoList from './components/zustand/TodoList';

function App() {

    const AppContainer = styled.div`
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        min-height: 100vh;
        width: 100vw;
        padding: 24px;
        text-align: center;
        transition: all 0.3s;
    `;

    const Section = styled.section`
        width: 100%;
        max-width: 800px;
        margin: 0 auto;
        padding: 18px;
        border-radius: 8px;
        margin-bottom: 20px;
    `;

    return (
        <>
            <AppContainer>
                <Section>
                    <h2>Zustand 전역 상태 관리</h2>
                    <CounterDisplay />
                    <CounterControls />
                </Section>
                <Section>
                    <h2>Zustand TodoList</h2>
                </Section>
                <Section>
                    <TodoList />
                </Section>
            </AppContainer>
        </>
    );
}

export default App;

 

[ TodoList.jsx ]

** TodoList.jsx **

import React from 'react';
import styled from 'styled-components';
import useTodoStore from '../../store/useTodoStore';

const ListContainer = styled.div`
    width: 100%;
    max-width: 600px;
    margin: 0 auto;
`;
const TodoItem = styled.div`
    display: flex;
    align-items: center;
    padding: 12px;
    margin: 8px 0;
    border-radius: 4px;
`;

const Checkbox = styled.input`
    margin-right: 12px;
    width: 18px;
    height: 18px;
    cursor: pointer;
`;

const TodoText = styled.span`
    flex: 1;
    text-decoration: ${(porps) => (porps.completed ? 'line-through' : 'none')};
`;

const DeleteButton = styled.button`
    padding: 6px 12px;
    color: white;
    background: red;
    border-radius: 4px;
    cursor: pointer;

    &:hover {
        opacity: 0.9;
    }
`;
const FilterContainer = styled.div`
    display: flex;
    gap: 10px;
    margin-bottom: 20px;
    justify-content: center;
`;

const FilterButton = styled.button`
    padding: 6px 12px;
    color: white;
    background: blue;
    border-radius: 4px;
    cursor: pointer;

    &:hover {
        opacity: 0.9;
    }
`;

const TodoList = () => {
    const { getFilteredTodos, toggleTodo, deleteTodo, setFilter } = useTodoStore();

    const todos = getFilteredTodos();

    return (
        <ListContainer>
            <FilterContainer>
                <FilterButton onClick={() => setFilter('all')}>전체</FilterButton>
                <FilterButton onClick={() => setFilter('active')}>진행중</FilterButton>
                <FilterButton onClick={() => setFilter('completed')}>완료</FilterButton>
            </FilterContainer>
            {todos.map((todo) => (
                <TodoItem key={todo.id}>
                    <Checkbox type="checkbox" checked={todo.completed} onChange={() => toggleTodo(todo.id)} />
                    <TodoText completed={todo.completed}>{todo.text}</TodoText>
                    <DeleteButton onClick={() => deleteTodo(todo.id)}>삭제</DeleteButton>
                </TodoItem>
            ))}
        </ListContainer>
    );
};

export default TodoList;

 

[ useTodoStore.js ]

import { create } from 'zustand';

const useTodoStore = create((set, get) => ({
    todos: [
        {
            id: 1,
            text: '밥먹기',
            completed: false,
        },
        {
            id: 2,
            text: '잠자기',
            completed: false,
        },
        {
            id: 3,
            text: '숨쉬기',
            completed: false,
        },
    ],
    filter: 'all', // all, active, completed

    toggleTodo: (id) =>
        set((state) => ({
            todos: state.todos.map((todo) => (todo.id === id ? { ...todo, completed: !todo.completed } : todo)),
        })),
    deleteTodo: (id) =>
        set((state) => ({
            todos: state.todos.filter((todo) => todo.id !== id),
        })),
    setFilter: (filter) => set({ filter }), // {filter : filter}
    getFilteredTodos: () => {
        const { todos, filter } = get();

        switch (filter) {
            case 'active':
                return todos.filter((todo) => !todo.completed);
            case 'completed':
                return todos.filter((todo) => todo.completed);
            default:
                return todos;
        }
    },
}));

export default useTodoStore;

 

위 코드에서 헷갈렸던 부분은 zustand의 전역 상태와 액션(함수) 부분을 구분하여 사용하는 방법과

set과 get의 역할, 그리고 어느 값을 전역에서 사용할지 말지가 헷갈렸다.

 

위 코드는 렌더링시에 useTodoStore에서 값을 가져오고 getFilterdTodos()로 필터링된 배열을 불러오고 있다.

 

이부분에서 필터링해서 가져오는 코드가 TodoList.jsx에 작성해야하는지, useTodoStrore.js에 작성해야하는지

저 필터링 된 부분을 어디서만 사용할지에 따라서 다르게 생각하면 됬었다.

 

현재 코드에서는 다른 부분에서도 필터링을 사용할 수 있다고 생각하여 전역으로 관리하는 useTodoStore에 작성했다.

 

이제 전역 상태와 액션을 구분하는 방식은 zustand는 create(()=>{}) 안에 key : value 형식으로 저장되어있는데,

 

이때 value가 일반 값이면 상태가 되고, 함수가 들어가면 액션이 된다.

 

set()을 사용하게 되면 콜백함수로 state를 사용할 수 있게되는데, 이건 필드( 상태 + 액션 )내용 전부에 접근할 수 있다.

 

get()또한 set() 안에서 사용할 수 있으며 차이는 state. 하고 접근하나 get(). 하고 접근하나의 차이가 끝이다.

 

zustand는 정말 간편하면서도 강력한 상태관리 라이브러리이다.

'Weekly TIL' 카테고리의 다른 글

Weekly TIL - Day 16  (2) 2025.04.30
Weekly TIL - Day 15  (2) 2025.04.29
Weekly TIL - Day 13  (0) 2025.04.27
Weekly TIL - Day 12  (0) 2025.04.25
Weekly TIL - Day 11  (1) 2025.04.25
'Weekly TIL' 카테고리의 다른 글
  • Weekly TIL - Day 16
  • Weekly TIL - Day 15
  • Weekly TIL - Day 13
  • Weekly TIL - Day 12
KoesJin
KoesJin
hEELo
  • KoesJin
    Seok DevLog
    KoesJin
  • 전체
    오늘
    어제
    • 분류 전체보기 (109)
      • Back End (31)
        • DataBase (15)
        • JAVA (12)
        • JDBC (4)
      • Front End (9)
        • HTML5 & CSS (3)
        • Java Script (6)
        • REACT (0)
      • Server (9)
        • JSP - TomCat - Servlet (7)
        • Spring Boot (2)
      • GitHub (1)
      • IT 지식 (기술면접 대비) (20)
      • Weekly TIL (39)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    from
    commit
    순서에 대하여
    weekly til - day 43
    DDL
    INNER JOIN
    GC
    weekly til - day 40
    weekly til - day 41
    View
    order by
    weekly til - day 38
    exception
    css
    DAO
    dml
    where
    select
    weekly til - day 39
    MVC 패턴
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
KoesJin
Weekly TIL - Day 14
상단으로

티스토리툴바