로컬 스토리지를 활용하여 사용자의 다크모드 설정, 일기 데이터, AI 답장을 저장하고 관리하는 기능을 구현했다.
페이지를 새로고침하거나 재방문해도 사용자의 데이터가 유지된다.
다크모드 설정 저장
설정 불러오기
애플리케이션 로드 시 로컬 스토리지에서 사용자의 마지막 다크모드 설정을 불러온다.
const ThemeProvider = ({ children }: ThemeProviderProps) => {
const loadDarkModeSetting = () => {
const storedDarkModeSetting = localStorage.getItem("darkMode");
return storedDarkModeSetting ? JSON.parse(storedDarkModeSetting) : false;
};
const [isDarkMode, setIsDarkMode] = useState(loadDarkModeSetting);
// ...
};
설정 저장
다크모드 상태가 변경될 때마다 로컬 스토리지에 저장한다.
useEffect(() => {
const body = document.querySelector("body");
isDarkMode ? body?.classList.add("dark") : body?.classList.remove("dark");
localStorage.setItem("darkMode", JSON.stringify(isDarkMode));
}, [isDarkMode]);

사용자가 선택한 다크모드 설정이 페이지 새로고침 후에도 유지된다.
일기 데이터 저장
Reducer를 통한 데이터 관리
일기 데이터의 생성, 수정, 삭제 작업이 발생할 때마다 로컬 스토리지에 저장한다.
function reducer(state: DiaryType[], action: ActionType) {
let nextState;
switch (action.type) {
case Action.INIT:
return action.data;
case Action.CREATE: {
nextState = [action.data, ...state];
break;
}
case Action.UPDATE: {
nextState = state.map((item) =>
String(item.id) === String(action.data.id) ? action.data : item
);
break;
}
case Action.DELETE: {
nextState = state.filter((item) => String(item.id) !== String(action.id));
break;
}
default:
return state;
}
localStorage.setItem("diary", JSON.stringify(nextState));
return nextState;
}
변경된 상태를 반환하기 전에 로컬 스토리지에 저장하여 데이터 동기화를 보장한다.
초기 데이터 불러오기
애플리케이션 시작 시 로컬 스토리지에서 저장된 일기 데이터를 불러와 초기 상태를 설정한다.
useEffect(() => {
const storedData = localStorage.getItem("diary");
if (!storedData) {
setIsLoading(false);
return;
}
const parsedData = JSON.parse(storedData);
if (!Array.isArray(parsedData)) {
setIsLoading(false);
return;
}
// 새로운 일기의 ID를 위해 최대 ID 계산
let maxId = 0;
parsedData.forEach((item) => {
if (item.id > maxId) {
maxId = item.id;
}
});
idRef.current = maxId + 1;
dispatch({
type: Action.INIT,
data: parsedData,
});
setIsLoading(false);
}, []);
저장된 데이터의 최대 ID를 계산하여 새로운 일기 생성 시 ID 충돌을 방지한다.
AI 답장 데이터 저장
답장 불러오기
일기 상세 페이지 진입 시 해당 일기의 AI 답장이 있는지 확인하고 표시한다.
useEffect(() => {
const diaries = getDiaries();
const currentDiary = diaries.find((diary) => diary.id === id);
if (currentDiary && currentDiary.gptAnswer) {
setGptAnswer(currentDiary.gptAnswer);
setHasReceived(true);
}
}, [id]);
답장 저장
AI 답장을 받으면 해당 일기 데이터에 답장을 추가하고 로컬 스토리지를 업데이트한다.
const handleClickAPICall = async () => {
try {
setIsLoading(true);
const message = await CallGPT({
prompt: JSON.stringify(content),
});
setHasReceived(true);
const parsedMessage = JSON.parse(message);
if (parsedMessage && parsedMessage.answer) {
const diaries = getDiaries();
const diaryIndex = diaries.findIndex((diary) => diary.id === id);
if (diaryIndex !== -1) {
diaries[diaryIndex].gptAnswer = parsedMessage.answer;
localStorage.setItem("diary", JSON.stringify(diaries));
}
setGptAnswer(parsedMessage.answer);
}
} catch (error) {
console.error(error);
} finally {
setIsLoading(false);
}
};
사용자가 일기 상세 페이지를 재방문할 때 이전에 받은 AI 답장을 다시 볼 수 있다.

'Dev Log' 카테고리의 다른 글
| [PeaNutter] TypeScript에서 버튼 클릭 이벤트 타입 에러 해결 (0) | 2025.11.08 |
|---|---|
| [PearNutter] 소셜미디어 앱 마이그레이션 계획 (0) | 2025.11.07 |
| [AI 감성 일기장] GPT API를 활용한 AI 답장 기능 구현 (0) | 2025.11.07 |
| [AI 감성 일기장] Tailwind CSS와 Context API를 활용한 다크모드 구현 (0) | 2025.11.07 |
| [AI 감성 일기장] Diary 페이지 일기 상세보기 기능 구현 (0) | 2025.11.07 |
