❄️
Recoil Selectors やってみた
前回の続き
Recoilの公式チュートリアルの続きをしました
source
最終的な構成
recoil-app $ tree src
src
├── App.css
├── App.js
├── App.test.js
├── RecoilState.js
├── TodoItem.js
├── TodoItemCreator.js
├── TodoList.js
├── TodoListFilters.js
├── TodoListStats.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
└── setupTests.js
0 directories, 14 files
RecoilState.js
import { atom , selector } from 'recoil';
export const todoListState = atom({
key: 'todoListState',
default: [],
});
export const todoListFilterState = atom({
key: 'todoListFilterState',
default: 'Show All',
});
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;
}
},
});
export const todoListStatsState = selector({
key: 'todoListStatsState',
get: ({get}) => {
const todoList = get(todoListState);
const totalNum = todoList.length;
const totalCompletedNum = todoList.filter((item) => item.isComplete).length;
const totalUncompletedNum = totalNum - totalCompletedNum;
const percentCompleted = totalNum === 0 ? 0 : totalCompletedNum / totalNum * 100;
return {
totalNum,
totalCompletedNum,
totalUncompletedNum,
percentCompleted,
};
},
});
App.js変更なし
import { TodoList } from './TodoList';
import { RecoilRoot } from 'recoil';
const App = () => {
return (
<RecoilRoot>
<h1>Todo List</h1>
<TodoList/>
</RecoilRoot>
);
}
export default App;
TodoList.js
import { useRecoilValue } from 'recoil';
import { filteredTodoListState } from "./RecoilState";
import { TodoItemCreator } from './TodoItemCreator';
import { TodoItem } from './TodoItem';
import { TodoListStats } from './TodoListStats';
import { TodoListFilters } from './TodoListFilters';
export const TodoList = () => {
const todoList = useRecoilValue(filteredTodoListState);
return (
<>
<TodoListStats />
<TodoListFilters />
<TodoItemCreator />
{todoList.map((todoItem) => (
<TodoItem key={todoItem.id} item={todoItem} />
))}
</>
);
}
TodoListStats
import { useRecoilValue } from "recoil";
import { todoListStatsState } from "./RecoilState";
export const TodoListStats = () => {
const {
totalNum,
totalCompletedNum,
totalUncompletedNum,
percentCompleted,
} = useRecoilValue(todoListStatsState);
const formattedPercentCompleted = Math.round(percentCompleted);
return (
<ul>
<li>Total items: {totalNum}</li>
<li>Items completed: {totalCompletedNum}</li>
<li>Items not completed: {totalUncompletedNum}</li>
<li>Percent completed: {formattedPercentCompleted}</li>
</ul>
);
}
TodoListFilters.js
import { useRecoilState } from "recoil";
import { todoListFilterState} from './RecoilState';
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>
</>
);
}
run
npm start
Discussion