typescript-todo
typescript-todo : createContext & useContext 작성
히치키치
2022. 8. 12. 19:03
💙 CreateContext
// /src/contexts/task-store.ts
import React, { createContext } from 'react';
import { Task } from '../types';
// 1. context 생성 : task가 원소인 리스트 (할 일들)
const TaskContext = createContext<
[Task[], React.Dispatch<React.SetStateAction<Task[]>>]
>([[], () => {}]);
export default TaskContext;
💙 useContext 훅 : useTaskStore
// /src/hooks/use-task-store.ts
import useLocalStorage from './use-local-storage';
import React, { useState, useContext, useEffect } from 'react';
import { Task } from '../types';
import { shuffle } from 'lodash';
import { nanoid } from 'nanoid';
import TaskContext from '../contexts/task-store';
const useTaskStore = () => {
// 1. useContext로 TaskContext 상태 사용
const [tasks, setTasks] = useContext(TaskContext);
// 2. FocusScreen에 띄울 할 일 id 설정
// useState로 초기값 정의
// filter 사용해 isComplete가 false로 구성된 task[] 만들고 그 중 첫번째 값의 id
const [focusedTaskId, setFocusedTaskId] = useState<string | undefined>(
tasks.filter((task) => !task.isComplete)[0]?.id
);
// 3. 2에서 정한 id에 해당하는 task를 tasks에서 find로 찾아서 값으로 설정
const focusedTask = tasks.find((task) => task.id === focusedTaskId);
// 4. task의 isComplete 여부를 update해 새로운 tasks 값 생성
const updateTaskCompletion = (taskId: string, isComplete: boolean) => {
// task의 id와 isComplete를 인자로 받음
setTasks((tasks) =>
tasks.map((task) => {
// tasks 배열을 map으로 돌면서
if (task.id === taskId) {
// 완료 여부가 변경된 task인 경우
return { ...task, isComplete };
//완료 여부를 update 해서 해당 task 요소를 반환
} else { // 완료 여부가 변경된 task가 아닌 경우
return task;
// 해당 task 요소 그대로 반환
}
})
);
};
useEffect(() => {
if (focusedTask?.isComplete) {
setFocusedTaskId(tasks.filter((task) => !task.isComplete)[0]?.id);
}
}, [tasks, focusedTask]);
// 5. filter를 통해 아직 완료되지 않은 할일 배열 생성
const shuffleFocusedTask = () => {
// filter를 통해 아직 완료되지 않은 할 일로만 구성된 배열 생성
// loadash 라이브러리의 shuffle 활용해 해당 배열의 순서를 바꿈
// 순서가 바뀐 배열의 첫번째 할 일을 focusScreen에 띄울 값으로 지정
setFocusedTaskId(shuffle(tasks.filter((task) => !task.isComplete))[0]?.id);
};
// 6. Pick 사용해 task 속성 중 label만 타입 검증
const addTask = (task: Pick<Task, 'label'>) => {
const id = nanoid();
setTasks((tasks) => [
...tasks, // 기존의 할 일들 갱신
{ id: id, label: task.label, isComplete: false }, // 새로운 할일 목록에 추가
]);
if (!focusedTaskId) {
//만약 최초로 task가 추가되어 focusScreen에 뜰 task가 지정되지 않은 상태인 경우
setFocusedTaskId(id); // 추가해...
}
};
const api = {
addTask,
focusedTask,
tasks,
setTasks,
updateTaskCompletion,
shuffleFocusedTask,
};
return api;
};
export default useTaskStore;