본문 바로가기
front-end/TypeScript

React + TypeScript로 만든 TodoList에 recoil 적용하기

by 행인데어 2023. 11. 7.

Recoil 사용이유

원래는 redux를 사용했었는데 TypeScript로 처음 프로젝트를 하면서 redux를 적용하려니 너무 어려웠음

그래서 redux보다 간단하다는 recoil을 사용해보기로 결정!!

(실제로 훨씬 사용하기 수월했다) 

 

Recoil 적용

1. 프로젝트에 Recoil 설치하기

npm i recoil

 

2. RecoilRoot로 App 컴포넌트 감싸주기

(index.tsx)
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { RecoilRoot } from 'recoil';

const root = ReactDOM.createRoot(
    document.getElementById('root') as HTMLElement
);
root.render(
    <React.StrictMode>
        <RecoilRoot>
            <App />
        </RecoilRoot>
    </React.StrictMode>
);

reportWebVitals();

 

recoil을 사용하기 위해서는 부모 컴포넌트에 RecoilRoot가 필요하고, 루트 컴포넌트에 넣으면 좋다.

 

3. Atom

Atom은 recoil에서 사용하는 state를 나타낸다.

key에는 유니크한 key값을, defualt에는 default 값을 넣어준다.

(recoil/atoms.ts)
import { atom } from 'recoil';

export interface TodoTypes {
    id: number;
    text: string;
    done: boolean;
}

export const todoState = atom<TodoTypes[]>({
    key:"todos",
    default:[],
});

 

4. Atom(state) 가져오고 수정하기 - useRecoilValue, useSetRecoilState, useRecoilState

useRecoilValue()는 atom에서 값을 읽어오고,

useSetRecoilState()는 atom의 값을 업데이트(설정) 해준다.

 

여기서는 사용하지 않았는데, useRecoilState()는 아래처럼 사용해서 atom의 값을 읽고, 업데이트할 수 있게 해준다.

const [text, setText] = useRecoilState(textState);

(todolist.tsx)
import React,{ useState, useEffect } from "react";
import TodoItem from "./todoItem";
import TodoInput from './todoInput';
import { TodoListContainer } from '../styles/todolist.styled'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { todoState, TodoTypes } from '../recoil/atoms';

const TodoList = () => {
    const [todoInput, setTodoInput] = useState<string>('');

    const todos = useRecoilValue<TodoTypes[]>(todoState);
    const setTodos = useSetRecoilState<TodoTypes[]>(todoState);

    const addItem = () => {
        const nextId = todos.length > 0? todos[todos.length-1].id + 1 : 0;
        
        const todo: TodoTypes = {
            id: nextId,
            text: todoInput,
            done: false
        }
        
        setTodos([...todos, todo]);
        setTodoInput('');
    }

    return(
        <TodoListContainer>
            <div 
                style={{paddingTop:"20px", fontSize:"25px"}}
            >To-Do List</div>
                <TodoInput 
                    todoInput={todoInput}
                    setTodoInput={setTodoInput}
                    addItem={addItem}
                    />
                <TodoItem
                    todos={todos}
                    setTodos={setTodos}
                />
        </TodoListContainer>
    )
}

export default TodoList;

 

5. 새로고침 후에도 state 유지하기 - Recoil-persist

Recoil-persist는 새로고침했을 때, 데이터가 날라가지 않게 해주는 라이브러리로
localStorage 또는 sessionStorage에 데이터를 저장해준다.

recoilPersist안에 지정을 해주는데, 지정해주지 않으면 기본값으로 localStorage에 저장이 된다.

Recoil-persist를 적용하려면 atom안에 effects_UNSTABLE를 추가해주어야 한다.

 

* 저장할 곳을 지정해주고 싶으면 아래처럼 해주면 된다.

const { persistAtom } = recoilPersist({
  key: '유니크한 키값',
  storage: sessionStorage,
});

(recoil/atoms.ts)
import { atom } from 'recoil';
import { recoilPersist } from 'recoil-persist';

const { persistAtom } = recoilPersist();

export interface TodoTypes {
    id: number;
    text: string;
    done: boolean;
}

export const todoState = atom<TodoTypes[]>({
    key:"todos",
    default:[],
    effects_UNSTABLE: [persistAtom]
});