코딩애플 리액트 기초부터 쇼핑몰 프로젝트까지! 강의를 들으면서 간단한 블로그를 만들어봤습니다.
결과물은 이렇습니다. 만들고보니까 별거 없는거 같은데 리액트 공부한지
일주일 정도 된 저에겐 좀 힘들었습니다 ㅎㅎ....
let [thumbsUp, setThumbsup] = useState([0, 0, 0]);
따봉 버튼 개수를 기록할 state를 만듭니다.
초기 화면엔 글이 3개 밖에 없으니까, 기록할 곳도 3개 만들어줍니다.
+useState(0)
이렇게 하나만 작성하면, 따봉 개수가 개별적으로 올라가지 않고,
동시에 올라가버립니다. 저장 공간이 하나밖에 없기 때문이죠!
let [title, setTitle] = useState(['남자 코트 추천', '강남 우동 맛집', '파이썬 독학']);
{title.map((a, i) => {
const addThumbsUp = () => {
let copy = [...thumbsUp]; //state 복사
copy[i]++; // 반복문 돌 때마다
setThumbsup(copy); //state 변경!
}
return (
<div className="list" key={i}>
<div className="list-head">
<h4>{a}</h4>
<button type="button" className='btnThumbsUp' onClick={() => {addThumbsUp();}}>
<span>👍{thumbsUp[i]}</span>
</button>
</div>
<div className="list-bottom">
<p>2월 17일</p>
</div>
</div>
);
})}
글 리스트는 map()
으로 state 안에 있는 값 개수만큼 반복 출력하도록 해주었습니다.
그리고, 따봉 증가 함수를 따로 만들어줬습니다.
그냥 onClick에 넣어도 되겠지만 함수로 만들어서 쓰는게 더 깔끔하고 간단할거 같아서
함수로 만들어줬습니다. copy[i]
이런식으로 i 파라미터를 넣어준 이유는 map 반복문에서
파라미터 i는 0,1,2 ... 이렇게 1씩 증가하는 정수를 나타내기 때문입니다 :)
let [modal, setModal] = useState(false);
let [modalTitle, setModalTitle] = useState(0);
Modal ui의 현재 상태를 state로 만듭니다.
안보일 땐 false , 보일 땐 true 이런식으로 state를 조작할려고 boolean으로 줬습니다.
modalTitle state는 0번째 글을 누르면 모달 창 타이틀도 0번째 글제목,
1번째 글을 누르면 모달 창 타이틀도 1번째 글 제목,
2번째 글을 누르면 모달 창 타이틀도 2번째 글 제목으로 바뀌어야 하기 때문에
모달 창 타이틀 state도 만들어줍니다.
{modal && <Modal bgColor={'skyblue'} titleProp={title} modalProp={setTitle} modalTitleProp={modalTitle}/>}
function Modal({bgColor, titleProp, modalProp, modalTitleProp}) {
const modalBackground = bgColor;
const listTitle = titleProp; // App 컴포넌트에서 title state
const modalListTitle = modalProp; //App 컴포넌트에서 setTitle state
const modalTitle = modalTitleProp; //App 컴포넌트에서 modalTitle state
return (
<div className="modal" style={{backgroundColor: modalBackground}}>
<h4>{listTitle[modalTitleProp]}</h4>
<p>날짜</p>
<p>상세내용</p>
</div>
);
}
Modal 컴포넌트를 만들고, App 컴포넌트에서 아까 글 리스트
저장해둔 title/setTitle state랑 , Modal ui 현재 상태를 나타내는 modal state , 글 제목 순서를 나타내는 ModalTitle state도 props로 전송해주었습니다.
추가로, es6 객체 비구조화 할당 문법? 을 사용하면 앞에 props.
을 안붙여도 된다는 피드백을
받아서 es6 문법을 활용해보았습니다.
비구조화 할당은 벨로퍼트님 모던 자바스크립트에서 참고했습니다!
const modalToggle = () => {
setModal((modal) => !modal);
};
글 제목을 누르면 modal이 보여야 하기 때문에 App 컴포넌트에서 modal state를 false에서 true로 바꿔주는 함수를 작성합니다.
{title.map((a, i) => {
const addThumbsUp = () => {
let copy = [...thumbsUp]; //state 복사
copy[i]++; // 반복문 돌 때마다
setThumbsup(copy); //state 변경!
}
return (
<div className="list" key={i}>
<div className="list-head">
<h4 onClick={() => {
modalToggle();
setModalTitle(i);
}}>{a}</h4>
<button type="button" className='btnThumbsUp' onClick={() => {addThumbsUp();}}>
<span>👍{thumbsUp[i]}</span>
</button>
</div>
<div className="list-bottom">
<p>2월 17일</p>
</div>
</div>
);
})}
글 리스트 반복문 부분으로 다시 돌아와서 글 제목 부분 (h4) 에 onClick 이벤트 핸들러를 달아서 아까 만들었던 modalToggle 함수를 넣어줍니다.
그리고, 글 제목을 누르면 모달 창 타이틀도 누른 글 제목으로 바뀌어야 하기 때문에
onClick 안에 반복문이 돌 때마다 실행되도록 해주었습니다.
const titleModfy = () => {
let writingModfiy = [...title];
writingModfiy[i] = '수정됐어!';
setTitle(writingModfiy);
}
map 반복문 안에 제목을 수정하는 함수를 만듭니다.
title state를 복사하고, 복사한 state를 반복문이 돌 때마다 수정됐어!
라는
글자로 바뀌게 하는 함수입니다.
(i 파라미터는 1씩 증가하는 정수이니까, 반복문이 돌면 wiritingModify[1],[2],[3] ...
이런식으로 됩니다.)
<button type='button' className='btnModify' onClick={() => {titleModfy();}}>
<span>✍️</span>
</button>
map 반복문 return 부분 안에 수정 버튼 하나 만들어서 onClick으로 함수 실행해주면 수정 버튼 만들기 끝!
let [input, setInput] = useState('');
사용자가 입력한 제목을 담는 state 하나 만들어줍니다.
(아무 문자열을 담고 싶으면, ''
따옴표 2개 치면 됩니다!)
<Input setInput={setInput} titleProp={title} inputProp={input} setTitleProp={setTitle}
thumbsUpProp={thumbsUp} setThumbsupProp={setThumbsup}/>
function Input({ setInput , titleProp , inputProp , setTitleProp , thumbsUpProp , setThumbsupProp}){
const textChange = setInput; //input state 변경함수
const listTitle = titleProp; //App에서 title state
const inputValue = inputProp; //App에서 input state
const addTitle = setTitleProp; //App에서 title state 변경함수
const currentThumbsUp = thumbsUpProp; //App에서 thumbsUp state
const addThumbsUp = setThumbsupProp; //App에서 thumbsUp state 변경함수
const inputOnChange = (e) => {
textChange(e.target.value);
console.log(textChange);
}
const inputOnSubmit = () => {
if(inputValue === ''){
alert('제목을 입력해주세요!');
return;
}
let currentValue = [...listTitle];
console.log(currentValue);
currentValue.unshift(inputValue);
console.log(currentValue);
addTitle(currentValue);
}
return (
<div className='inputGroup'>
<input type='text' onChange={inputOnChange}/>
<button type='button' className='btnSubmit' onClick={inputOnSubmit}>등록</button>
</div>
)
}
input 컴포넌트 하나 만들어서 App 컴포넌트에 있던 state들 전부 props로 전송해줍니다.
그리고...
const inputOnChange = (e) => {
textChange(e.target.value);
console.log(textChange);
}
onChange 될 때마다 input state에 입력한 데이터들 저장하라고 함수를 만들어줍니다.
+e.target.value
로 input에 입력한 값을 가져올 수 있습니다.
if(inputValue === ''){
alert('제목을 입력해주세요!');
return;
}
input state 안에 아무것도 없으면 얼럿 출력하고, 글이 추가되지 않게 종료시켜줍니다.
let currentValue = [...listTitle];
console.log(currentValue);
currentValue.unshift(inputValue);
console.log(currentValue);
addTitle(currentValue);
등록 버튼을 누르면 글이 추가되어야 하기 때문에, title state 복사를 하고
title state 배열 맨 앞에 사용자가 입력한 데이터 넣어주세요~ 라고 코드를 짰습니다.
+unshift
가 배열 맨 앞에 데이터를 추가할 수 있게 해주는 친구입니다.
<div className='inputGroup'>
<input type='text' onChange={inputOnChange}/>
<button type='button' className='btnSubmit' onClick={inputOnSubmit}>등록</button>
</div>
함수 다 짰으니까 return 부분에서 이벤트 핸들러 달아주면 글 추가 기능 끝!
const titleDelete = () => {
let writingDelete = [...title];
writingDelete.shift();
setTitle(writingDelete);
console.log(title);
shift()
메서드를 사용하여 title state 안에 있는 값 삭제해주는 함수를 만들었습니다.
+shift()
는 배열 안에 있는 첫번째 요소를 제거합니다.
<button type='button' className='btnDelete' onClick={() => {titleDelete();}}>
<span>🗑️</span>
</button>
함수 다 만들었으니 이벤트 핸들러 달아주면 글 삭제 버튼 끝!
글을 추가하고 따봉 버튼을 누르면 기존에 있던 글의 따봉 개수가 없어지는
이슈가 하나 생겼습니다.
let [thumbsUp, setThumbsup] = useState([0, 0, 0]);
이유는 따봉 개수를 담는 state 가 최대 3개밖에 없어서 생긴 이슈였습니다.
즉, 따봉 개수를 3개 이상 담을 공간이 없는것이죠.
let thumbsUpValue = [...currentThumbsUp];
thumbsUpValue.push(0);
addThumbsUp(thumbsUpValue);
그래서 글이 추가되면 따봉 개수 담는 state도 추가되게 해주었습니다!
+push()
는 배열에 맨 뒤에 요소를 추가해줍니다.
이렇게 해서 간단하지만 간단하지 않았던... 블로그를 만들어 보았습니다.
하면서 느낀건, 정말 쉽지 않다! 입니다. 쉬워보였던 것들도 막상 구현할려고 하면
너무 막막했어요. 평소에 제이쿼리만 쓰다가 바닐라 js 쓰려고 하니까 더 그런 거 같기도 합니다.
이제부턴 제이쿼리 말고 바닐라 js와 친해져야겠다는 생각이 들었고, 리액트 강의 다 듣게
되면 나중에 개인 프로젝트도 리액트로 한번 만들어봐야겠어요!
(어렵긴한데 은근 재밌는 매력이 있네요...)