React 새 상태 관리 라이브러리 Recoil 소개

49771 단어 ReactRecoiltech
새 상태 관리 라이브러리 Recoil은 2010/05 페이스북에서 발표되었습니다.
아직 실험적인 실행방식인 것 같지만 그동안의 상태관리 방법에는 없는 매력이 있으니 한번 시도해보자.

리콜 뭐 좋아해요?


React에서 가장 유명한 상태 관리자는 Redux입니다.
Redux는 루트 어셈블리와 같은 상위 어셈블리를 통해 Provider를 설정합니다.
1 응용 프로그램은 거대한 state 트리를 가지고 있다.
이렇게 하면 구성 요소에서도 Redux의 모든 state에 접근할 수 있습니다.
전 세계의 변수가 쉽게 사용되는 것은 당연한 일이며, 복잡해지면 그 영향의 범위가 갑자기 불분명해지고 의도하지 않은 부작용에 시달릴 수도 있다.
이러한 배경에서 구성 요소 내에서 상태를 가진 분할 통치가 트렌드가 되었고 Recoil은 이 문제를 해결하는 선택이다.
Recoil<RecoilRoot>은 다음 구성 요소만 state에 접근할 수 있기 때문에 범위가 잠긴 상태를 처리할 수 있습니다.
Context API는 범위 내에서 구현할 수 있습니다.
Context 내state 업데이트 시 구독한 구성 요소가 다시 렌더링되어 성능이 나빠지거나 구성 요소의 상태가 재설정됩니다.
이 부분은 리코일과 레드룩스가 잘 하고 있어요.

Recoil 자습서의 설명


Recoil 공식 자습서를 따라 Recoil을 사용하는 Todo 애플리케이션을 설치합니다.
기본적으로 튜토리얼을 그대로 소개하는 코드인데 기술을 생략한 부분이 많아 마지막에 실행할 수 있도록 일부 수정했다.
GiitHub 코드만 보고 싶은 사람은 기사에 링크를 붙여 놓았다.
· 추가 ToDo 프로젝트
· ToDo 프로젝트 편집
· ToDo 프로젝트 삭제
· ToDo 프로젝트 필터링
• 각 상태에 대한 통계 표시
등 기능의 실현.

차리다


먼저 강좌에서 생략한 부분의 해설부터 시작한다.
React 환경을 준비하고 npm 또는 yarn에 recoil을 설치합니다.
npm install recoil
yarn add recoil
Recoil을 통한 상태 관리 섹션을 Redux와 Context에 해당하는 Provider의 RecoilRoot로 둘러쌉니다.
이번 해설은 최소 구성으로 이뤄졌다.tsx의 RecoilRoot을 읽고 있습니다.
실제 응용 프로그램에서 RecoilRoot을 읽으면 역할 범위를 최소화할 수 있습니다.
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {RecoilRoot} from 'recoil';

import {TodoList} from '~/components/TodoList';

ReactDOM.render(
  <>
    <RecoilRoot>
      <TodoList />
    </RecoilRoot>
  </>,
  document.getElementById('root')
);

Atoms


Atoms는 데이터 저장소를 가리킨다
key는 응용 프로그램을 통해 독특하고default에서 초기 값을 설정합니다.
이렇게 하면 Todo 프로젝트에 넣을 todoListState를 준비할 수 있습니다.
import {atom} from 'recoil';

export const todoListState = atom({
  key: 'todoListState',
  default: [],
});
use Recoil Value ()를 사용하여 TodoList 구성 요소가 방금 만든 todoListate를 읽습니다.
TodoListFilters, TodoListStats 구성 요소는 나중에 제작되기 때문에 논평을 합니다.
import * as React from 'react';
import {useRecoilValue} from 'recoil';

import {todoListState} from '~/recoil/atoms';

import {
  // TodoListStats,
  // TodoListFilters,
  TodoItemCreator,
  TodoItem,
} from '~/components';

export const TodoList = () => {
  const todoList = useRecoilValue(todoListState);

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

      {todoList.map(todoItem => (
        <TodoItem key={todoItem.id} item={todoItem} />
      ))}
    </>
  );
};
새 Todo 프로젝트를 추가하는 TodoItemCreator를 만듭니다.
Atoms를 업데이트하기 위해서,useSetRecoilState () 에서 업데이트 대상의 todoListState를 제출해서 setter 함수를 가져옵니다.
레드ux의 액션에 해당하는 것을 준비하지 않았기 때문에 업데이트된 값을 setTodoList에 직접 전달합니다.
import * as React from 'react';
import {useSetRecoilState} from 'recoil';

import {todoListState} from '~/recoil/atoms';

// utility for creating unique Id
let id = 0;
const getId = () => {
  return id++;
};

export const TodoItemCreator = () => {
  const [inputValue, setInputValue] = React.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>
  );
};
목록의 각 항목에 대해 TodoItem 구성 요소를 생성합니다.
이 구성 요소를 사용하면 텍스트 수정/삭제 항목/작업 상태 (boolean) 를 변경할 수 있습니다.
방금 사용한 useSetRecoilState () 는 setter 함수만 되돌려주고,use RecoilState () 라면 [값,setter 함수] 를 되돌려줍니다.
React.usestate()와 같네요.
import * as React from 'react';
import {useRecoilState} from 'recoil';

import {todoListState} from '~/recoil/atoms';

const replaceItemAtIndex = (arr, index, newValue) => {
  return [...arr.slice(0, index), newValue, ...arr.slice(index + 1)];
};

const removeItemAtIndex = (arr, index) => {
  return [...arr.slice(0, index), ...arr.slice(index + 1)];
};

export const TodoItem = ({item}) => {
  const [todoList, setTodoList] = useRecoilState(todoListState);
  const index = todoList.findIndex(listItem => listItem === item);

  const editItemText = ({target: {value}}) => {
    const newList = replaceItemAtIndex(todoList, index, {
      ...item,
      text: value,
    });

    setTodoList(newList);
  };

  const toggleItemCompletion = () => {
    const newList = replaceItemAtIndex(todoList, index, {
      ...item,
      isComplete: !item.isComplete,
    });

    setTodoList(newList);
  };

  const deleteItem = () => {
    const newList = removeItemAtIndex(todoList, index);

    setTodoList(newList);
  };

  return (
    <div>
      <input type="text" value={item.text} onChange={editItemText} />
      <input
        type="checkbox"
        checked={item.isComplete}
        onChange={toggleItemCompletion}
      />
      <button onClick={deleteItem}>X</button>
    </div>
  );
};
이로써 Todo 프로그램의 간단한 일람 표시와 텍스트의 변경/항목 삭제/작업의 상태를 변경할 수 있습니다 (boolean).

Selectors


Atoms만 충분히 사용할 수 있지만, Atoms state를 가공한 값을 반환하는 함수를 정의하는 Selectors라는 개념도 있습니다.
Vuex가 말한 getters와 맞먹는다.
Recoil 튜토리얼에서는 Todo 목록을 작업 상태에서 필터링하여 각 상태의 개수를 가져올 수 있습니다.
우선, Atoms는 현재 어떤 필터가 걸려 있는 todoListFilter State를 추가합니다. Atoms에는 'Show All' | 'Show Completed' 의 임의의 필터가 있습니다.
export const todoListFilterState = atom({
  key: 'todoListFilterState',
  default: 'Show All',
});
Atoms의 todoListState에서 todoListFilterState의 조건에 따라 필터된 Filtered TodoListState를 제작한다.
import {selector} from 'recoil';

import {todoListState, todoListFilterState} from '~/recoil/atoms';

export const filteredTodoListState = selector({
  key: 'filteredTodoListState',
  get: ({get}) => {
    const filter = get(todoListFilterState);
    const list = get(todoListState);

    switch (filter) {
      case 'Show Completed':
        return list.filter(item => item.isComplete);
      case 'Show Uncompleted':
        return list.filter(item => !item.isComplete);
      default:
        return list;
    }
  },
});
TodoListState 구성 요소로 TodoListate를 필터하는 FilteredTodoListState를 가져옵니다.
이로써 모든 이벤트(todoListState)에 표시된 목록은 필터된 목록으로 대체됩니다.
// import { todoListState } from '~/recoil/atoms'
import {filteredTodoListState} from '~/recoil/selectors';

//const todoList = useRecoilValue(todoListState)
const todoList = useRecoilValue(filteredTodoListState);
TodoListFilters 어셈블리를 추가합니다.이 구성 요소는 select 요소가 변경되면 todoListFilter State를 업데이트합니다.
제작이 끝나면Tsx의 TodoListFilters에 대한 논평을 제거하십시오.
import * as React from 'react';
import {useRecoilState} from 'recoil';

import {todoListFilterState} from '~/recoil/atoms';

export const TodoListFilters = () => {
  const [filter, setFilter] = useRecoilState(todoListFilterState);

  const updateFilter = ({target: {value}}) => {
    setFilter(value);
  };

  return (
    <>
      Filter:
      <select value={filter} onChange={updateFilter}>
        <option value="Show All">All</option>
        <option value="Show Completed">Completed</option>
        <option value="Show Uncompleted">Uncompleted</option>
      </select>
    </>
  );
};
이렇게 하면 Todo 목록의 필터 기능을 실현할 수 있다.
다음은 Todo 목록의 개수와 비율입니다.
· ToDo 프로젝트의 총 수량
· 완성 항목 총수
· 미완성 항목의 총수
• 프로젝트 완성 비율
목록을 가져오는 선택기 todoListState를 추가합니다.
export const todoListStatsState = selector({
  key: 'todoListStatsState',
  get: ({get}) => {
    const todoList = get(filteredTodoListState);
    const totalNum = todoList.length;
    const totalCompletedNum = todoList.filter(item => item.isComplete).length;
    const totalUncompletedNum = totalNum - totalCompletedNum;
    const percentCompleted = totalNum === 0 ? 0 : totalCompletedNum / totalNum;

    return {
      totalNum,
      totalCompletedNum,
      totalUncompletedNum,
      percentCompleted,
    };
  },
});
todoListState를 표시하는 TodoListState 구성 요소를 만듭니다.
제작이 끝나면Tsx의 TodoListStats에 대한 논평을 없애주세요.
import * as React from 'react';
import {useRecoilValue} from 'recoil';

import {todoListStatsState} from '~/recoil/selectors';

export const TodoListStats = () => {
  const {totalNum, totalCompletedNum, totalUncompletedNum, percentCompleted} =
    useRecoilValue(todoListStatsState);

  const formattedPercentCompleted = Math.round(percentCompleted * 100);

  return (
    <ul>
      <li>Total items: {totalNum}</li>
      <li>Items completed: {totalCompletedNum}</li>
      <li>Items not completed: {totalUncompletedNum}</li>
      <li>Percent completed: {formattedPercentCompleted}</li>
    </ul>
  );
};
Filtered Todo List State, todo List State 2개의 selector를 제작하여 상태에서 여과된 목록, 각 상태의 건수와 비례를 얻을 수 있다.

총결산


리코일은 후크스 이후 태어나 사용하기 편하고 맞춤 제작된 고리와 잘 어울리는 느낌이다.
리액트뿐만 아니라 레드ux/Vuex도 모든 것에서 등록된 전단에서 이탈하는 경향적인 부분이 있기 때문에 이 절차가 가속화되겠죠.
데이터 흐름을 정리하는 것이 유용하기 때문에 정식 발표가 되면 적극적으로 활용하고 싶다.
이 글의 코드는 GiitHub에 공개되었다.
https://github.com/ria3100/react-recoil-example

좋은 웹페이지 즐겨찾기