인프런 커뮤니티 질문&답변
isLoading 기능 추가했는데, 존재하지 않는 일기 입니다.
작성
·
33
0
isLoading 기능을 추가했는데
수정하기, 다이어리 페이지에서 새로고침하면 존재하지 않는 일기입니다. 라고 나오네요.
https://github.com/pdh9311/onebite-react 작성했던 코드 입니다.
import { Route, Routes } from "react-router-dom";
import "./App.css";
import { createContext, useEffect, useReducer, useRef, useState } from "react";
import Diary from "./pages/Diary";
import Edit from "./pages/Edit";
import Home from "./pages/Home";
import New from "./pages/New";
import Notfound from "./pages/Notfound";
function reducer(state, action) {
let nextState;
switch (action.type) {
case "INIT":
return action.data;
case "CREATE":
nextState = [action.data, ...state];
break;
case "UPDATE":
nextState = state.map((item) =>
String(item.id) === String(action.data.id) ? action.data : item
);
break;
case "DELETE":
nextState = state.filter(
(item) => String(item.id) !== String(action.data.id)
);
break;
default:
nextState = state;
}
localStorage.setItem("diary", JSON.stringify(nextState));
return nextState;
}
export const DiaryStateContext = createContext();
export const DiaryDispathContext = createContext();
function App() {
const [isLoading, setIsLoading] = useState(true);
const [data, dispatch] = useReducer(reducer, []);
const idRef = useRef(0);
useEffect(() => {
const storedData = localStorage.getItem("diary");
if (!storedData) {
setIsLoading(false);
return;
}
const parsedData = JSON.parse(storedData);
if (!Array.isArray(parsedData)) {
setIsLoading(false);
return;
}
let maxId = 0;
parsedData.forEach((item) => {
if (Number(item.id) > maxId) {
maxId = Number(item.id);
}
});
idRef.current = maxId + 1;
console.log(parsedData);
dispatch({
type: "INIT",
data: parsedData,
});
setIsLoading(false);
}, []);
const onCreate = (createdDate, emotionId, content) => {
dispatch({
type: "CREATE",
data: {
id: idRef.current++,
createdDate,
emotionId,
content,
},
});
};
const onUpdate = (id, createdDate, emotionId, content) => {
dispatch({
type: "UPDATE",
data: {
id,
createdDate,
emotionId,
content,
},
});
};
const onDelete = (id) => {
dispatch({
type: "DELETE",
data: {
id,
},
});
};
if (isLoading) {
<div>데이터 로딩중입니다....</div>;
}
return (
<>
<DiaryStateContext.Provider value={data}>
<DiaryDispathContext.Provider value={{ onCreate, onUpdate, onDelete }}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/new" element={<New />} />
<Route path="/diary/:id" element={<Diary />} />
<Route path="/edit/:id" element={<Edit />} />
<Route path="*" element={<Notfound />} />
</Routes>
</DiaryDispathContext.Provider>
</DiaryStateContext.Provider>
</>
);
}
export default App;
import { useContext, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { DiaryStateContext } from "../App";
//커스텀 훅
const useDiary = (id) => {
const data = useContext(DiaryStateContext);
const [currDiaryItem, setCurrDiaryItem] = useState();
const nav = useNavigate();
useEffect(() => {
console.log("useDiary");
const currentDiaryItem = data.find(
(item) => String(item.id) === String(id)
);
if (!currentDiaryItem) {
window.alert("존재하지 않는 일기입니다.");
nav("/", { replace: true });
}
setCurrDiaryItem(currentDiaryItem);
}, [id]);
return currDiaryItem;
};
export default useDiary;
답변 3
0
안녕하세요 padohy님 이정환입니다.
작성하신 코드를 자세히 살펴보니 문제의 원인은 useDiary.jsx 파일에 있었습니다.
padohy님께서는 useDiary Hook 내부에 작성된 useEffect의 의존성 배열에 id만 포함시켜 두셨는데요

강의중에 안내드리는 코드는 아래 그림과 같이 의존성 배열에 id, data가 모두 포함됩니다.

따라서 data를 의존성 배열에 추가해 주시면 문제 없이 기능이 다 잘 작동할 것 입니다.
0
안녕하세요, 인프런 AI 인턴입니다. padohy님께서 겪고 계신 문제를 함께 해결해 볼 수 있도록 하겠습니다.
질문하신 코드에서는 새로고침 했을 때 “존재하지 않는 일기입니다.“라는 경고창이 뜨는 문제가 있다고 하셨습니다. 이는 리액트의 useEffect 가 상태나 props가 변경될 때마다 실행되기 때문에 발생할 수 있습니다. 다음은 문제의 원인과 해결책입니다:
데이터 로딩 상태 확인:
useEffect내부에서data배열을 확인하는데,data가 아직 로딩되지 않은 경우에도 실행될 수 있습니다. 초기 로딩 상태를 확인하는 로직이 필요합니다.
useEffect의존성 배열 수정:- 현재
useEffect는id만 의존성 목록에 들어가 있습니다. 하지만data도 포함하여 데이터가 변경될 때마다 실행되어야 합니다.
- 현재
로딩 중일 때
useDiary실행 방지:- 데이터가 충분히 로드되지 않은 상태에서
useDiary가 실행되면 문제가 발생할 수 있습니다.isLoading상태를 사용하여 로딩이 완료된 후에만useDiary가 작동하도록 조건을 추가해야 합니다.
- 데이터가 충분히 로드되지 않은 상태에서
수정된 useDiary 훅의 예시는 다음과 같습니다:
const useDiary = (id) => {
const data = useContext(DiaryStateContext);
const [currDiaryItem, setCurrDiaryItem] = useState();
const nav = useNavigate();
useEffect(() => {
if (data && data.length > 0) {
const currentDiaryItem = data.find((item) => String(item.id) === String(id));
if (!currentDiaryItem) {
window.alert("존재하지 않는 일기입니다.");
nav("/", { replace: true });
}
setCurrDiaryItem(currentDiaryItem);
}
}, [id, data]); // data를 의존성 배열에 추가
return currDiaryItem;
};
위 코드에서 data를 의존성 배열에 추가함으로써 데이터가 변동될 때마다 useEffect가 실행되어 최신 상태를 반영할 수 있습니다. 또한, if (data && data.length > 0)를 통해 데이터가 없을 때의 실행을 방지할 수 있습니다.
이와 관련된 문제 해결 방법에 대한 추가 참고 자료로는 이 유사한 질문을 참고하실 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
-1
isLoading 상태는 localStorage.getItem() 가 비동기가 아니므로 제대로 값을 변경할 수 없어서.
계속 true 로 '데이터 로딩중...' 만 반환할 수 있습니다.
우선은 isLoading 상태값을 false 로 초기화 하고서 useEffect 내에서 localStorage.getItem('daiary') 하기전에 true로 변경하고 코드를 진행해 보세요.
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
setIsLoading(true);
const storedData = localStorage.getItem("diary");
if (!storedData) {
setIsLoading(false);
return;
}
const parsedData = JSON.parse(storedData);
if (!Array.isArray(parsedData)) {
setIsLoading(false);
return;
}
let maxId = 0;
parsedData.forEach((item) => {
if (Number(item.id) > maxId) {
maxId = Number(item.id);
}
});
idRef.current = maxId + 1;
console.log(parsedData);
dispatch({
type: "INIT",
data: parsedData,
});
setIsLoading(false);
}, []);



