ํˆฌ๋‘๋ฆฌ์ŠคํŠธ Recoil๋กœ ๋ฆฌํŒฉํ† ๋ง
728x90

Today, What I learned?

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์™€ ๋ฆฌ๋•์Šค ํˆดํ‚ท์œผ๋กœ ๋ฆฌํŒฉํ† ๋ง ํ–ˆ๋˜ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฆฌ์ฝ”์ผ๋กœ ํ•œ๋ฒˆ ๋” !.. ๋ฆฌํŒฉํ† ๋งํ•ด๋ณด์•˜๋‹ค. 

(์ตํ˜€๋ณด๊ธฐ์— ํˆฌ๋‘๋ฆฌ์ŠคํŠธ๋งŒํ•œ ๊ฒƒ์ด ์—†๋‹ค..)
๋ฆฌ์ฝ”์ผ์— ๋Œ€ํ•ด ๊ฐ„๋žตํ•˜๊ฒŒ ์ •๋ฆฌํ•ด๋ณด๊ณ  ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •์„ ๊ธฐ๋กํ•œ๋‹ค.

 

 

Recoil

๋ฆฌ์ฝ”์ผ์€ facebook์—์„œ ์ถœ์‹œํ•œ ๋ฆฌ์•กํŠธ๋ฅผ ์œ„ํ•œ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค.
๋งŽ์ด๋“ค ์‚ฌ์šฉํ•˜๋Š” ๋ฆฌ๋•์Šค๋ณด๋‹ค ๋ณด์ผ๋Ÿฌ ํ”Œ๋ ˆ์ดํŠธ๊ฐ€ ์ ๊ณ ,
์•ก์…˜, ๋ฆฌ๋“€์„œ, ๋””์ŠคํŒจ์น˜.. ์™€ ๊ฐ™์ด ์•Œ์•„์•ผ ํ•  ๊ธฐ๋ณธ ๊ฐœ๋…์ด ๋งŽ์€ ๋ฆฌ๋•์Šค์— ๋น„ํ•ด ์ƒ๋Œ€์ ์œผ๋กœ ์‰ฝ๊ฒŒ ์ตํž ์ˆ˜ ์žˆ๋‹ค.


๋˜ ์‚ฌ์šฉ๋ฐฉ๋ฒ•์ด useState ํ›…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋“ฏํ•˜๋‹ค.
๋ฆฌ๋•์Šค์—์„  ๋น„๋™๊ธฐ ์ž‘์—…์„ ์œ„ํ•ด Redux-thunk๋‚˜ Redux-saga ๊ฐ™์€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ข€ ๋” ์–ด๋ ต๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋ฆฌ์ฝ”์ผ์—์„œ๋Š” ๋‚ด์žฅ๋œ Selector๋ฅผ ํ†ตํ•ด ๋น„๋™๊ธฐ ๋กœ์ง์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๊ธฐ๋ณธ์ ์ธ Recoil ๊ฐœ๋…

RecoilRoot

๋ฆฌ๋•์Šค์˜ Provider ๊ฐ™์€ ๊ฐœ๋…์ด๋‹ค. ๋ฃจํŠธ ์ปดํฌ๋„ŒํŠธ์— ๊ฐ์‹ธ์ค€๋‹ค.

 

 

Atom

์ƒํƒœ์˜ ์ผ๋ถ€๋‹ค. atom์„ ๊ตฌ๋…ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ์–ด๋””์—์„œ๋‚˜ atom์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ๋‹ค.
atom()์œผ๋กœ ์„ ์–ธ์„ ํ•˜๋Š”๋ฐ, key์™€ default ๊ฐ’์„ ํ•„์ˆ˜์ ์œผ๋กœ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค.

import { atom } from 'recoil';

export const textState = atom({
  key: 'textState', // atom์„ ์‹๋ณ„ํ•˜๋Š” ์ „์—ญ์ ์œผ๋กœ ๊ณ ์œ ํ•œ ๊ฐ’
  default: '', // ์ดˆ๊นƒ๊ฐ’. ๋‹ค๋ฅธ atom์ด๋‚˜ selector๋„ ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
});

 

 

useRecoilState()

์ปดํฌ๋„ŒํŠธ์—์„œ useState()๋ฅผ ์“ฐ๋“ฏ์ด atom์„ ์ฝ๊ณ  ์“ฐ๋Š” ๋ฐ์— ์‚ฌ์šฉํ•˜๋Š” ํ›….
์ด ํ›… ์™ธ์—๋„ atom์„ ์ฝ์„ ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” useRecoilValue(), ์“ธ ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” useSetRecoilState() ํ›… ๋“ฑ์ด ์žˆ๋‹ค.

์ƒํƒœ๊ฐ’๊ณผ setter ํ•จ์ˆ˜๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค. atom ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž๋™์ ์œผ๋กœ ๋ฆฌ๋ Œ๋”๋ง ๋œ๋‹ค.

import React from 'react';
import { useRecoilState } from 'recoil';
import { textState } from './atoms';

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

  const onChange = (e) => setText(e.target.value);

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
      <div>{text}</div>
    </div>
  );
};

export default CharacterCoutner;

 

 

๊ฐ„๋‹จํ•œ ๊ฐœ๋…์€ ์ด ์ •๋„๋กœ ์‚ดํŽด๋ณด๊ณ  Selector ๋“ฑ์˜ ๊ฐœ๋…์€ ๊ณต์‹๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด ๋ณด์ž!...
https://recoiljs.org/ko/docs/introduction/installation

 

์„ค์น˜ | Recoil

NPM

recoiljs.org

 

์ด์ œ ๋ณธ๊ฒฉ์ ์ธ ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •.

 

Recoil ์„ค์น˜

๋ฆฌ์ฝ”์ผ์„ ์„ค์น˜ํ•ด ์ค€๋‹ค.

npm install recoil

yarn add recoil

 

 

Recoil ์„ค์ •

index.tsx์— ๊ธฐ์กด์˜ redux provider ๋Œ€์‹ ์— RecoilRoot๋กœ ๊ฐ์‹ธ์ค€๋‹ค.

import App from './App';
import { RecoilRoot } from 'recoil';

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

 

 

State ์„ค์ •

recoil ํด๋” ์•ˆ์— state๋ฅผ ๋„ฃ์„ ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค.
ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ์ ํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— atom์— ํƒ€์ž…์„ ๋ณ„๋„๋กœ ์„ ์–ธํ•ด ์ฃผ์—ˆ๋‹ค.
์ฒซ ๋ Œ๋”๋ง์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋“ค์–ด๊ฐ€ ์žˆ์„ ๊ฐ’์ด ํ•„์š”ํ•ด์„œ default์˜ ๋ฐฐ์—ด ๊ฐ’์— ๊ฐ’๋“ค์„ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค.

import { atom } from 'recoil';
import { TodoType } from '../components/todoForm/TodoForm';
import { v4 as uuid } from 'uuid';

export const todoState = atom<TodoType[]>({
  key: 'todos',
  default: [
    {
      id: uuid(),
      title: '๋ฆฌ์•กํŠธ ๊ณต๋ถ€',
      content: '๋ฆฌ์•กํŠธ ์ˆ™๋ จ๊ฐ•์˜ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ณต์Šตํ•˜๊ธฐ',
      isDone: false,
    },
   ...
  ],
});

 

 

์ ์šฉ

Todo ์ถ”๊ฐ€

useState๋ฅผ ์“ฐ๋“ฏ์ด useRecoilState() ํ›…์œผ๋กœ ์œ„์— ๋งŒ๋“  state๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค.

  const [todos, setTodos] = useRecoilState<TodoType[]>(todoState);

  ...

  const submitHandler = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    ...

    const newTodo: TodoType = {
      id: uuid(),
      title,
      content,
      isDone: false,
    };

    setTodos([...todos, newTodo]); // setTodos๋กœ ์ „์—ญ์ƒํƒœ์— ์ถ”๊ฐ€ํ•ด์ฃผ๊ธฐ

    setTitle('');
    setContent('');

    return true;
  };

 

 

Todo ์™„๋ฃŒ ํ† ๊ธ€, ์‚ญ์ œ

๊ธฐ์กด ๋ฆฌ๋“€์„œ์˜ reducers ์•ˆ์—์„œ ์ด๋ฃจ์–ด์ง€๋˜ ๋กœ์ง์ด ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜ ์•ˆ์—์„œ ์ด๋ฃจ์–ด์ง„๋‹ค๊ณ  ๋ณด๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

 const [todos, setTodos] = useRecoilState<TodoType[]>(todoState);

  // ํˆฌ๋‘ ์™„๋ฃŒ/์ทจ์†Œ ํ† ๊ธ€ ํ•ธ๋“ค๋Ÿฌ
  const toggleDoneHandler = (id: string) => {
    const newState = todos.map((item) => {
      return item.id === id
        ? {
            ...item,
            isDone: !item.isDone,
          }
        : item;
    });

    setTodos(newState);
  };

  // ํˆฌ๋‘ ์‚ญ์ œ ํ•ธ๋“ค๋Ÿฌ
  const deleteTodoHandler = (id: string) => {
    if (window.confirm('ํ•ด๋‹น ํˆฌ๋‘๋ฅผ ์ •๋ง ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?')) {
      const newTodos = todos.filter((todo) => todo.id !== id);
      setTodos(newTodos);
    }
  };

 

 

Todo ์ƒ์„ธ

state์˜ ๊ฐ’๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, useRecoilValue() ํ›…์œผ๋กœ setterํ•จ์ˆ˜ ์—†์ด state๊ฐ’๋งŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

const Detail = () => {
  const todos = useRecoilValue<TodoType[]>(todoState);
  const param = useParams();

  // id์™€ ์ผ์น˜ํ•˜๋Š” ํˆฌ๋‘ ์ฐพ๊ธฐ
  const todo = todos.find((item) => item?.id === param?.id);

 

 

Todo ์ˆ˜์ •

todo ์ˆ˜์ •๋„ ์œ„์™€ ๋น„์Šทํ•˜๊ฒŒ ๋ฆฌ๋“€์„œ์— ์ž‘์„ฑํ–ˆ๋˜ ๋กœ์ง์„ ๊ฐ€์ ธ์™€์„œ ์‰ฝ๊ฒŒ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 const [todos, setTodos] = useRecoilState<TodoType[]>(todoState);

 ...

  const editTodoHandler = (id: string) => {
    ...

      const newState = todos.map((item) => {
        return item.id === id
          ? {
              ...item,
              title: newTitle,
              content: newContent,
            }
          : item;
      });

      setTodos(newState);
    }

    setIsEdit(!isEdit);
  };

 

 

์ด๋ฏธ์ง€๊ฐ€ ์ž‘์•„์กŒ์ง€๋งŒ.. ์•„๋ฌดํŠผ ๋ฆฌํŒฉํ† ๋ง ์™„๋ฃŒ!...

ํ™•์‹คํžˆ ๋ฆฌ๋•์Šค์— ๋น„ํ•ด ๊ฐ€๋ณ๊ณ  ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

728x90