[2차 프로젝트][숙박플랫폼][Recoil] 모달창과 달력 전역 상태관리하기

GY·2022년 1월 15일
0

리액트

목록 보기
43/54
post-thumbnail

Recoil이란?

✔️ Atom

기존 리덕스의 스토어와 유사한 개념으로, 상태의 단위
atom이 업데이트 되면, 해당 atom을 구독하고 있던 모든 컴포넌트들의 state가 새로운 값으로 리렌더링 된다.
각 atom은 고유한 id인 key값으로 구분되며, 여러 컴포넌트에서 atom을 구독하고 있다면 그 컴포넌트들도 똑같은 상태를 공유한다.


💎 Atom 생성하는 방법

atom()함수를 사용한다.

const todoListState = atom({
  key: 'todoListState',
  default: [],
});

이 atom에는 고유한 key와 default값을 주어야 한다.


💎 Atom을 업데이트하는 방법

🔹 useRecoilValue

useRecoilValue에 생성한 atom을 인자로 넣어 읽어올 수 있는 todoList를 생성해주었다.

function TodoList() {
  const todoList = useRecoilValue(todoListState);

  return (
    <>
      {/* <TodoListStats /> */}
      {/* <TodoListFilters /> */}
      <TodoItemCreator />

      {todoList.map((todoItem) => (
        <TodoItem key={todoItem.id} item={todoItem} />
      ))}
    </>
  );
}

🔹 useSetRecoilState

atom인 todoListState내용을 업데이트 하기 위해서는 useSetrecoilState훅을 사용해 준다.

function TodoItemCreator() {
  const [inputValue, setInputValue] = useState('');
  const setTodoList = useSetRecoilState(todoListState);

  const addItem = () => {
    setTodoList((oldTodoList) => [
      ...oldTodoList,
      {
        id: getId(),
        text: inputValue,
        isComplete: false,
      },
    ]);
    setInputValue('');
  };

  const onChange = ({target: {value}}) => {
    setInputValue(value);
  };

  return (
    <div>
      <input type="text" value={inputValue} onChange={onChange} />
      <button onClick={addItem}>Add</button>
    </div>
  );
}

// 고유한 Id 생성을 위한 유틸리티
let id = 0;
function getId() {
  return id++;
}

🔹 이 예시를 보면 이해가 간다.

import * as React from 'react';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { _num } from './modules/recoil/numberRecoil';

const App = (): JSX.Element => {
    
    const [num, setNum] = useRecoilState<number>(_num); // getter와 setter를 동시에 가져올 경우
    // const num = useRecoilValue<number>(_num); // getter만 가져올 경우
    // const setNum = useSetRecoilState<number>(_num); // setter만 가져올 경우

    const onClickIncrease = () => {
        setNum(num+3); // 3만큼 증가
    }

    const onClickDecrease = () => {
        setNum(num-2); // 2만큼 감소
    }

    return (
        <div>
            <p>현재 값: {num}</p>

            <button onClick={onClickIncrease}>증가</button>
            <button onClick={onClickDecrease}>감소</button>
        </div>
    )
}

export default App;

  1. userecoilstate로 num이라는 상태값을 정의해주었다.
  2. useSetrecoilstate를 사용해 num 상태값을 변경해준다.
  3. useRecoilValue를 사용해 변경된 num 상태값을 읽어온다.

💎 Hooks

  • useRecoilState: atom을 읽고 쓰려고 할 때
  • useRecoilValue: atom을 읽기만 할 때
  • usesetrecoilstate: atom에 쓰려고만 할 때
  • useResetRecoilState: atom을 초깃값으로 초기화할 때


✔️ Selector

export const countInputState = selector({
    key: 'countTitleState',
    get: ({ get }) => {
        return `현재 카운트는 ${get(countState)} 이고 입력값은 ${get(inputState)} 입니다.`;
    },
    set: ({ set }, newValue) => { // 2번째 파라미터 에는 추가로 받을 인자를 나타냅니다.
        set(countState, Number(newValue)); // count atom 수정
        set(inputState, newValue + ''); // input atom 수정
    },
});

countInputState라는 함수를 selector로 만들었다.

import { useRecoilState } from 'recoil';
import { countState, inputState, countInputState } from '../../../recoil/count';

function SelectorCount() {
    const [ count, setCount ] = useRecoilState(countState); // useRecoilState 을 통한 value, setter 반환
    const [ input, setInput ] = useRecoilState(inputState); // useRecoilState 을 통한 value, setter 반환
    const [ countInput, setCountInput ] = useRecoilState(countInputState);

    return (
        <div>
            <h2>읽기 쓰기 카운트 컴포넌트</h2>
            <p>카운트 {count}</p>
            <p>selector {countInput}</p>
            <input value={input} onChange={(e) => setInput(e.target.value)} />
            <button onClick={() => setCount(count + 1)}>숫자 증가</button>
            <button onClick={() => setCount(count - 1)}>숫자 감소</button>
            <button onClick={() => setCountInput('9999')}>selector 값 9999로 변경</button>
        </div>
    );
}

export default SelectorCount;

userecoilstate에 countinputState을 넣어 countInput이라는 상태값을 만들었다.
이것은 그대로 문장으로 리턴되어 보여진다.
태값을 생성했다.



적용하기

💎 Atom 생성

별도의 파일에서 달력에서 선택한 날짜를 저장하는 selectedDatesState atom을 생성했다.

//globalState.js
import { atom } from 'recoil';

export const selectedDatesState = atom({
  key: 'selectedDatesState',
  default: {
    checkin: null,
    checkout: null,
  },
});

💎 Atom에 값 업데이트하기

달력 컴포넌트에서는 날짜를 선택하면 선택한 날짜정보를 저장해주어야 한다. useRecoilState를 사용해 날짜정보를 저장하고 읽을 수 있도록 해준다.

//selectedDate.js
const [selectedDates, setSelectedDates] = useRecoilState(selectedDatesState);

  return (
      <Calendar
        onSelect={(startDate, endDate, validDateRange) => {
          validDate(validDateRange);
          setSelectedDates({
            ...selectedDates,
            check_in: startDate,
            check_out: endDate,
          });
        }}

💎 Atom에서 값 가져와 사용하기

Modal에서는 검색 버튼을 눌렀을 때 달력 컴포넌트에서 선택한 날짜 값을 받아와 url에 쿼리스트링으로 넘겨주어야 하기 때문에 selectedDatesState의 값을 읽어와야한다.
useRecoilValue를 이용해 이 값을 읽어온다.

//Modal.js

  const selectedDates = useRecoilValue(selectedDatesState);


Reference

profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.

0개의 댓글