리액트에 대한 기억 끌어올리기 위한 강의 따라하기 프로젝트...
만들어 볼 메모메모장의 기본 화면.
디폴트 값으로 가장 최신 메모가 노출되고
작성, 수정 버튼은 따로 없이 쓰자마자 바로 업데이트 되는 형식.
사이드 바에서 메모의 타이틀을 누르면 해당 메뉴가 노출되고
+ 버튼을 누르면 새 메모가 생성된다.
삭제 버튼도 있는데 그건 지금 이 글을 쓰고 있는 단계에선 아직 안만들었고
기능 구현 하면서 만들 예정!
일단 여기까지의 과정
강의 들을때는 따라가기 급급해서 흐름 파악이 안되길래 뼈대를 그려보았다.
근데 넘 간단함... ㅎㅎㅎㅎ
사실 원래는 데이터 흐름을 그려보려했는데 그 자잘한걸 다 그려놓고 시작하는게
불가능하다는걸 깨닫고 그냥 이렇게 끝냈음.
흐름도대로 파일을 만들고 더미데이터를 만들어서
컴포넌트들로 보내주었다.
input과 textarea의 value를 memoDatas의 값으로 고정해놨기 때문에
현재 상태에선 텍스트를 입력해도 내용이 변경되지 않는다.
텍스트 입력시 내용이 변경되도록 수정해주자.
1. onChange 감지하기
2. memoDatas의 데이터에 새로 입력한 텍스트 추가해주기
MemoContainer 컴포넌트
<div className="memo-title">
<input
type="text"
value={memo.title}
onChange={(e) => {
console.log(e.target.value);
}}
/>
</div>
<div className="memo-contents">
<textarea
value={memo.content}
onChange={(e) => {
console.log(e.target.value);
}}
/>
</div>
App 컴포넌트
const updateMemoData = (newMemo) => {
const newMemos = [...memoDatas];
newMemos[selectedMemoIndex] = newMemo;
setMemoDatas(newMemos)
}
updateMemoData 함수를 만들어서 newMemo 값을 가져온다.
newMemos라는 이름으로 memoDatas를 복사해온뒤
newMemos의 현재선택된 index의 값을 newMemo로 업데이트.
그리고 newMemos의 내용으로 memoData를 업데이트 해준다.
MemoContainer 컴포넌트
<div className="memo-title">
<input
type="text"
value={memo.title}
onChange={(e) => {
updateMemoData({
...memo,
title: e.target.value,
})
}}
/>
</div>
<div className="memo-contents">
<textarea
value={memo.content}
onChange={(e) => {
updateMemoData({
...memo,
content: e.target.value,
})
}}
/>
</div>
updateMemoData 함수를 받아와서 인자로 타이핑 된 값을 전달해준다.
1. 클릭이벤트 감지하기
2. 클릭시 selectedMemoIndex 변경
MemoList 컴포넌트
<ul className="memo-list">
{memoDatas && memoDatas.map((memo, index) => (
<MemoItem
key={index}
index={index}
isSelected={index === selectedMemoIndex}
onClickItem={() => {
console.log('clicked');
}}
>{ memo.title }</MemoItem>
))}
</ul>
onClickItem 함수를 생성하여 MemoItem에 전달하면!
MemoItem을 클릭할 때마다 콘솔에 잘 출력된다.
MemoList 컴포넌트
function MemoList({ memoDatas, selectedMemoIndex, setSelectedMemoIndex }) {
return(
<ul className="memo-list">
{memoDatas && memoDatas.map((memo, index) => (
<MemoItem
key={index}
index={index}
isSelected={index === selectedMemoIndex}
onClickItem={() => {
setSelectedMemoIndex(index)
}}
>{ memo.title }</MemoItem>
))}
</ul>
)
}
위에서부터 setSelectedMemoIndex를 받아와서 현재의 index로 변경해준다.
잘 된다!
1. 버튼 클릭시 새 메모 데이터 생성하기
2. setSelectedMemoIndex를 새로운 메모의 index로 변경하기
클릭 감지는 위에서 한 작업과 동일하니 바로 생성으로 넘어가보자
SideBarFooter 컴포넌트
function SideBarFooter({ onClickAdd }) {
return(
<div className="side-bar__footer">
<button
className="btn-add"
onClick={onClickAdd}
>
+
</button>
</div>
)
}
add 함수를 App 컴포넌트에서 관리할 것이기 때문에 위에서부터 함수를 받아온다.
App 컴포넌트
function App() {
...
const addMemoItem = () => {
setMemoDatas([
{
title: '제목',
content: '',
},
...memoDatas,
])
}
return (
<div className="App">
<div className='memo-project'>
...
<MemoContainer
memo={memoDatas[selectedMemoIndex]}
updateMemoData={updateMemoData}
/>
</div>
</div>
);
}
addMemoItem 함수를 추가해서
memoDatas의 맨 앞에 새 아이템을 추가해준다.
원래 제목도 빈 문자열로 생성하려 했는데
이렇게 보여서... 디폴트 텍스트를 추가해주었다.
const addMemoItem = () => {
setMemoDatas([
{
title: '제목',
content: '',
},
...memoDatas,
])
setSelectedMemoIndex(0)
}
addMemoItem에서 selectedMemoIndex를 0으로 변경해준다.
아주 간단하다!
어디서 추가하든 새로 생성된 메모가 활성화된다.
대망의 마지막..! 삭제하기만 구현해주면 끝..!
1. 삭제 버튼 추가하기
2. 삭제 동작 구현하기
3. 아이템이 하나밖에 없을 때 삭제하기
MemoItem 컴포넌트
function MemoItem({ children, isSelected, onClickItem, onClickDelete }) {
...
<button
className="memo-item__delete"
onClick={onClickDelete}
>X</button>
}]
MemoList 컴포넌트
function MemoList({ memoDatas, selectedMemoIndex, setSelectedMemoIndex }) {
...
onClickDelete={(e) => {
e.stopPropagation();
console.log('delete');
}}
}
삭제버튼 클릭시 클릭이벤트가 부모요소인 MemoItem으로 전달되어
삭제해야 할 아이템이 포커스 되어버린다.
이 문제를 해결하기 위해 delete함수에 e.stopPropagation을 추가해준다.
* e.stopPropagation :
이벤트가 상위 엘리먼트에 전달되지 않게 막아 주는 역할을 한다.
delete 함수가 실행되어 콘솔에 delete가 추가되지만
no.01 메모가 선택되지 않는다.
onClick 이벤트를 App.js에서 관리하면 addItem이 실행된 후에 deleteItem이 실행되어 오류가 발생하기 때문에
MemoList에서 이 동작을 해주어야한다.
아이템의 수가 0일때 MemoContainer에서 input과 textarea의 value 값으로 가져올 데이터가 없어
에러가 발생한다.
데이터 없음 처리를 해주자.
MemoContainer 컴포넌트
function MemoContainer({ memo, updateMemoData }) {
if(!memo){
return <div className="nodata">
<div className="nodataItem">
<h1>메모가 없습니다.</h1>
<h2>새로운 메모를 추가해주세요.</h2>
</div>
</div>
}
...
}
flex를 이용해 텍스트를 MemoContainer 영역의 한 가운데에 띄우고싶어서
nodataItem div로 한 번 더 감싸주었다.
끝!!!!!
강의로 볼 땐 지루해서 죽을 뻔 했는데
복습한다고 혼자 해보니까 너무 재밌다.
강의 보지 말고 그냥 바로 개인 프로젝트 들어가야겠다...
[JS] javascript로 달력 만들기 ② (0) | 2024.07.13 |
---|---|
[JS] javascript로 달력 만들기① (0) | 2024.07.11 |
[JS] javascript로 계산기 만들기 (0) | 2024.07.07 |
[JS] javascript로 Todo list 만들기 ③ - localStorage에 저장하고 가져오기 (0) | 2024.07.07 |
[JS] javascript로 Todo list 만들기 ② - 할 일 완료와 삭제하기 (0) | 2024.07.06 |
댓글 영역