ex) 앞서 블로그를 만들었던 코드에 좋아요 버튼을 만들어보자.
import React, { useState } from 'react';
import './App.css'
function App() {
let[title, setTitle] = useState(['일상 기록', '상품 리뷰']);
let[like, setLike] = useState(0);
return (
<div className="App">
<div className="posts">
<h3>{ title[0] } <span>❤</span> 0 </h3>
<p>2021년 7월 8일</p>
</div>
<div className="posts">
<h3>{ title[1] } <span>❤</span> 0 </h3>
<p>2021년 7월 8일</p>
</div>
</div>
)
}
좋아요를 누를 수 있도록 span 태그를 이용해 ❤를 만들었고,
이제 ❤를 누를 때 마다 옆의 숫자가 올라가도록 만들어야 한다.
이때 좋아요의 숫자는 변경되는 데이터이므로 useState를 사용해 초기값을 0으로 정해주는 코드를 추가했다.
let [like, setLike] = useState(0);
좋아요 갯수를 의미하는 like, 그 데이터를 변경하는 setLike 함수가 생겼다.
이제 ❤를 누를 때 숫자 데이터를 변경하기 위해 span 태그에 onclick 속성을 추가했다.
자바스크립트에서는
<span onclick="실행할 자바스크립트"></span>
이지만, 리액트 JSX에서는 조금 다르게 사용한다.
<span onClick={실행할 함수}>❤</span>
위의 방식으로 사용하며, 자바스크립트와 다른점은
<span onClick={ 함수명 }>❤</span>
<span onClick={ function() {실행할 코드} }>❤</span>
<span onClick={ () => {실행할 코드} }>❤</span>
또한, 위의 세 경우 모두 사용 가능하다.
이제 onClick에 들어갈 함수를 작성해야 한다.
만약 like가 일반 변수였다면
<span onClick={ () => {like + 1} }>❤</span>
위와 같은 코드로 실행시킬 수 있다.
하지만 useState를 사용하면서 setLike라는 like데이터를 변경하는 함수를 같이 만들었기 때문에 setLike라는 함수를 사용해 변경해주어야 한다.
사용법은
setLike(대체할 데이터) 이다.
(setLike 함수의 ()안에 있는 데이터로 완전히 대체해준다.)
따라서
<span onClick={ () => {setLike(like + 1)} }❤</span>
위와 같은 방법으로 데이터를 변경해줄 수 있다.
import React, { useState } from 'react';
import './App.css'
function App() {
let[title, setTitle] = useState(['일상 기록', '상품 리뷰']);
let[like, setLike] = useState(0);
return (
<div className="App">
<div className="posts">
<h3>{ title[0] } <span onClick={() => {setLike(like + 1)}}>❤</span> 0 </h3>
<button onClick={}>제목 바꾸기</button>
<p>2021년 7월 8일</p>
</div>
<div className="posts">
<h3>{ title[1] } <span onClick={() => {setLike(like + 1)}}>❤</span> 0 </h3>
<p>2021년 7월 8일</p>
</div>
</div>
)
}
위의 코드에서 버튼을 눌렀을 때 첫번째 글 제목인 '일상 기록'을 '6월 일상'으로 바꾸려고 한다.
따라서
<button onClick={}>제목 바꾸기</button>
제목을 바꿀수 있는 버튼을 먼저 만들었다.
그리고 좋아요 숫자를 바꾸는것과 같이 제목 변경 함수인 setTitle 함수를 사용하여 제목을 바꿔주어야 한다.
function changeTitle() {
setTitle(['6월 일상', '상품 리뷰']);
}
이 경우에는 title 데이터가 배열 형태여서(길어서) 제목을 바꾸는 함수를 따로 만들었다.
왜 안 바꾸는 '상품 리뷰' 까지 다 써서 넣어주나요?
state 변경함수들은 state를 완전히 대체하는 것이기 때문
따라서 ['일상 기록', '상품 리뷰']를 대체할 새로운 배열을 넣어주어야 한다.
2) 에서 한 것 처럼 setTitle함수를 사용하여 배열을 대체 해 주어도 되지만, 배열 요소가 100만개라고 생각하면... 😇 불가능하다. (어쩌면 가능하지 않을까..? 는 상상하기 싫음)
따라서
function changeTitle() {
var newTitle = [...title];
newTitle[0] = '6월 일상';
setTitle(newTitle);
}
위와 같이 바꿔보았다.
위의 코드는
- title을 완전히 복사한 복사본을 newTitle이라고 한 뒤,
- 그 중 첫번째 값인 newTitle[0]을 '6월 일상' 으로 바꿔준다.
- 그리고 setTitle함수(title 변경함수)를 사용하여 title 배열의 값을 바꿔준다.
var newTitle = [...title];
이렇게 title앞에 ...을 쓰는 이유? 그냥
var newTitle = title;
로 쓰면 되는거 아닌가?
...은 spread 연산자라고 하는 ES6 문법이다.
Array나 Object 자료형 왼쪽에 붙일 수 있다.
spread 없이 그냥 등호를 사용한 경우도 title에 있는 자료를 newTitle에 복사한다는 뜻이지만,
각각 데이터를 별개로 저장하는 것이 아니고 같은 값을 공유하는 것이다.
따라서 title을 변경하면 newTitle도 변경된다.
그래서 state로 만든 데이터도 완전한 개별 복사본이 필요하다.
이때 완전한 복사본을 만드는 방법은 ...(spread)를 사용하는 것이다.
(shallow/deep copy라고 부른다.)
...(spread)는 배열 [], 객체 {} 안의 값을 꺼내쓸 수 있게 해주는 문법이다.
그래서
var newTitle = [...title];
위 코드에서 [...title]은 title 값을 꺼내서 다시 배열로 만들어준다는 뜻이다.
따라서 완전히 독립적인 배열 복사본이 생성된다.