[React] 간단한 블로그 만들기!

P1ush·2022년 8월 21일
3

React

목록 보기
9/10

https://codingapple.com/course/react-basic/

코딩애플 리액트 기초부터 쇼핑몰 프로젝트까지! 강의를 들으면서 간단한 블로그를 만들어봤습니다.

결과물은 이렇습니다. 만들고보니까 별거 없는거 같은데 리액트 공부한지
일주일 정도 된 저에겐 좀 힘들었습니다 ㅎㅎ....


어떤 기능이 있는지?

  1. 따봉 버튼을 누르면 개수가 올라갑니다. (이 때, 개수는 개별적으로)
  2. 글 제목을 누르면 모달 창이 보여지며, 글 제목을 눌렀을 때 모달 창 타이틀도 같이 바뀌어야 합니다.
  3. 글 수정 버튼을 누르면 제목이 수정 됩니다.
  4. input에 제목 적고 등록 버튼을 누르면 글이 추가됩니다. (이 때, input 안에 아무것도 없을때 등록 버튼을 누르면 동작하지 않습니다.)
  5. 삭제 버튼을 누르면 글이 삭제 됩니다.



👍 따봉 버튼을 누르면 개수 올라가게 하기

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>217</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 문법을 활용해보았습니다.

https://learnjs.vlpt.us/basics/06-object.html

비구조화 할당은 벨로퍼트님 모던 자바스크립트에서 참고했습니다!



 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>217</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와 친해져야겠다는 생각이 들었고, 리액트 강의 다 듣게
되면 나중에 개인 프로젝트도 리액트로 한번 만들어봐야겠어요!
(어렵긴한데 은근 재밌는 매력이 있네요...)

0개의 댓글