REACT 를 사용하면서 자주 만나볼 수 있는 버그들에 대한 대처방법
1. key 값 중복
버그 재현을 위해 2개의 일기를 작성한다. 개발자 도구 콘솔에 보면 Warning 이 뜨는 것을 확인할 수 있다.
- 콘솔
react-dohttp://m.development.js:86 Warning: Encountered two children with the same key, `1`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.
2개의 자식이 똑같은 key 를 가졌다는 버그이다. App 컴포넌트에서 id 를 설정하는 useRef() 초기값을 0 으로 설정했기 때문이다. dummy data 의 데이터가 5개 이므로, 초기값을 6으로 설정한다.
- App.js
...
// ID 설정
const dataId = useRef(6);
...
2. 오타
DiaryList 컴포넌트의 정렬 state 의 초기값이 'lastest' 로 설정된 부분을 'latest' 로 수정한다. 자바스크립트를 사용할 때는 항상 오타에 주의한다(오타를 막아주는 기능을 가진 타입스크립트도 있다).
- App.js
import React, { useReducer, useRef } from 'react';
import './App.css';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Home from './pages/Home';
import New from './pages/New';
import Edit from './pages/Edit';
import Diary from './pages/Diary';
// state 처리
const reducer = (state, action) => {
let newState = [];
switch (action.type) {
case 'INIT': {
return action.data;
}
case 'CREATE': {
/*
const newItem = {
...action.data
};
newState = [newItem, ...state];
*/
newState = [action.data, ...state];
break;
}
case 'REMOVE': {
newState = state.filter((it) => it.id !== action.targetId);
break;
}
case 'EDIT': {
newState = state.map((it) => it.id === action.data.id ? { ...action.data } : it);
break;
}
default:
return state;
}
return newState;
}
// state context
export const DiaryStateContext = React.createContext();
// dispatch context
export const DiaryDispatchContext = React.createContext();
// dummy data
const dummyData = [
{
id: 1,
emotion: 1,
content: '오늘의 일기 1번',
date: '1707509600000' // new Date().getTime()
},
{
id: 2,
emotion: 2,
content: '오늘의 일기 2번',
date: '1707509600001' // new Date().getTime() + 1
},
{
id: 3,
emotion: 3,
content: '오늘의 일기 3번',
date: '1707509600002' // new Date().getTime() + 2
},
{
id: 4,
emotion: 4,
content: '오늘의 일기 4번',
date: '1707509600003' // new Date().getTime() + 3
},
{
id: 5,
emotion: 5,
content: '오늘의 일기 5번',
date: '1707509600004' // new Date().getTime() + 4
},
/*
{// 먼 미래
id: 6,
emotion: 2,
content: '오늘의 일기 6번',
date: 1807035077876
}
*/
];
function App() {
// const [data, dispatch] = useReducer(reducer, []);
const [data, dispatch] = useReducer(reducer, dummyData);
// console.log(new Date().getTime() + 1);
// ID 설정
const dataId = useRef(6);
// CREATE
const onCreate = (date, content, emotion) => {
dispatch({
type: 'CREATE',
data: {
id: dataId.current,
date: new Date(date).getTime(),
content,
emotion
}
});
dataId.current += 1;
};
// REMOVE
const onRemove = (targetId) => {
dispatch({ type: 'REMOVE', targetId });
};
// EDIT
const onEdit = (targetId, date, content, emotion) => {
dispatch({
type: 'EDIT',
data: {
id: targetId,
date: new Date(date).getTime(),
content,
emotion
}
});
};
return (
<DiaryStateContext.Provider value={data}>
<DiaryDispatchContext.Provider
value={{
onCreate,
onRemove,
onEdit
}}
>
<BrowserRouter>
<div className="App">
<Routes>
<Route path='/' element={<Home />} />
<Route path='/new' element={<New />} />
<Route path='/edit/:id' element={<Edit />} />
<Route path='/diary/:id' element={<Diary />} />
</Routes>
</div>
</BrowserRouter>
</DiaryDispatchContext.Provider>
</DiaryStateContext.Provider>
);
}
export default App;
- DiaryList.js
...
// 정렬 state
const [sortType, setSortType] = useState('latest');
...
App 컴포넌트 dummy data 의 날짜를 특정 날짜로 고정했다.
3. 달의 마지막 날짜로 일기 작성시 목록에서 안 보임
새 일기작성시 해당 월의 마지막날 선택 후 일기 작성 완료 시, 목록에 일기가 출력되지 않으나 개발자 도구의 Reducer 에서는 새로 작성한 일기가 잘 들어와 있는 것을 볼 수 있다. Home 컴포넌트의 날짜를 필터링하는 useEffect 에서 마지막 날짜를 설정할 때, 0시 0분 0초가 아닌 그날의 끝시간인 23시 59분 59초로 설정한다.
- Home.js
...
// 받은 데이터 이번달 범위로 필터링
useEffect(() => {
if (diaryList.length >= 1) {
const firstDay = new Date(curDate.getFullYear(), curDate.getMonth(), 1).getTime(); // 이번년도 이번달 1일 밀리세컨즈
const lastDay = new Date(curDate.getFullYear(), curDate.getMonth() + 1, 0, 23, 59, 59).getTime(); // 이번년도 이번달 마지막일 밀리세컨즈
setData(diaryList.filter((it) => firstDay <= it.date && it.date <= lastDay));
}
}, [curDate, diaryList]); // diaryList 가 바뀌었다는건 일기가 추가, 수정, 삭제됨을 의미하므로 추가
...
자바스크립트에서 시간 객체를 사용하여 시간 비교시, 시, 분, 초까지 영향을 미친다.
참고강의 : https://www.inflearn.com/course/%ED%95%9C%EC%9E%85-%EB%A6%AC%EC%95%A1%ED%8A%B8#
한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지 강의 - 인프런
개념부터 독특한 프로젝트까지 함께 다뤄보며 자바스크립트와 리액트를 이 강의로 한 번에 끝내요. 학습은 짧게, 응용은 길게 17시간 분량의 All-in-one 강의!, 리액트, 한 강의로 끝장낼 수 있어요.
www.inflearn.com
'강의 실습 > 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지' 카테고리의 다른 글
프로젝트 최적화 (1) | 2024.02.13 |
---|---|
LocalStorage를 일기 데이터베이스로 사용하기 (1) | 2024.02.12 |
페이지 구현 - 일기 상세 (/diary) (2) | 2024.02.10 |
페이지 구현 - 일기 수정 (/edit) (2) | 2024.02.09 |
페이지 구현 - 일기쓰기 (/new) (0) | 2024.02.08 |
댓글