무작위로 필요한 문제만 검색해서 개발했던 리액트였기 때문에 기본기를 다지고자 개념부터 차근차근 정리하면서 공부하는 포스팅입니다😄
같은 동작을 하는 코드를 HTML과 js로 짰을 때와 리액트로 짰을 때를 비교해 봅시다.
<html>
<body>
<div class ="todo">
<h3>할 일 목록</h3>
<ul class="list></ul>
<input class="desc" type="text" />
<button onclick="onAdd()">추가</button>
<button onclick="onSaveToServer()">서버에 저장</button>
</div>
<script>
let currentId = 1;
const todoList = [];
function onAdd() {
const descEl = document.querySelector('.todo .desc');
const todo = { id : currentId++, desc: descEl.value };
todoList.push(todo);
const listEl = document.querySelector('.todo .list');
const todoEl = makeTodoElement(todo);
list.appendChild(todoEl);
}
/* 생략 */
</script>
</body>
</html>
import React, { useState } from 'react';
export default function App() {
const [todoList, setTodoList] = useState([]);
const [currentId, setCurrentId] = useState(1);
const [desc, setDesc] = useState('');
function onAdd() {
const todo = { id: currentId, desc };
setCurrentId(currentId + 1);
setTodoList([...todoList, todo]);
}
function onDelete(e) {
const id = Number(e.target.dataset.id);
const newTodoList = todoList.filter(todo => todo.id !== id);
setTodoList(newTodoList);
}
function onSaveToServer() {}
return (
<div>
<h3>할 일 목록</h3>
<ul>
{todoList.map(todo => {
<li key={todo.id}>
<span>{todo.id}</span>
<button data-id = {todo.id} onClick={onDelete}>
삭제
</button>
</li>
))}
</ul>
<input type="text" value={desc} onChange={e => setDesc(e.target.value)} />
<button onClick={onAdd}>추가</button>
<button onClick={onSaveToServer}>서버에 저장</button>
</div>
);
}
html은 명령형 프로그래밍 -> dom api 사용해야 요소 접근 할 수 있음
리액트는 선언형 프로그래밍 -> 가상 돔 사용
const [todoList, setTodoList] = useState([]);
setCount({ ...count, value: count.value + 1 });
const [color, setColor] = useState("red");
function onClick() {
setColor('blue");
}
return (
<button style={{ backgroundColor: color }} onclick = {onClick}>좋아요</button>
);
: 컴포넌트 내에 변경 가능한 데이터 저장소로 가변값임
: 같은 컴포넌트가 여러개 쓰이더라도 상태값을 위한 자신만의 메모리가 있어 각자의 상태값을 유지함
Title.js
export default function Title({ tite }) {
return <p>{title}</p>
}
Counter.js
export default function Counter() {
const [count, setCount] = useState(0);
function onClick() {
setCount(count + 1);
}
return (
<div>
<Title title={`현재 카운트 : ${count}` />
<button onClick={onClick}>증가</button>
</div>
);
}
카운터 컴포넌트에서 타이틀 컴포넌트를 사용,
부모컴포넌트가 렌더링 될 때마다 자식 컴포넌트가 같이 렌더링 됨.
: 속성값이 변경 될 때만 컴포넌트가 렌더링 되게 하기 위한 라이브러리
: 자식 컴포넌트의 속성값에 변경이 있을 경우에만 렌더링 됨
Title.js
function Title({ tite }) {
return <p>{title}</p>
}
export default React.memo(Title);
같은 컴포넌트가 여러개 쓰이더라도 상태값을 위한 자신만의 메모리가 있어 각자의 상태값을 유지함
📍 리액트는 상태값 변경 유무를 이전값과의 단순 비교로 하는데 객체의 참조값은 변하지 않고 단순히 내부의 속성값만 변경이 된 상태라면 리액트 입장에서는 값이 변경되지 않았다고 판단함. 아래 코드는 화면이 변하지 않음
export default function Counter() {
const [count, setCount] = useState({ value : 0 });
function onClick() {
count.value += 1; //여기서 값 직접 수정
setCount(count);
}
return (
<div>
<Title title={`현재 카운트 : ${count}` />
<button onClick={onClick}>증가</button>
</div>
);
}
리액트는 컴포넌트 함수의 반환값으로 다음과 같은 값을 반환 할 수 있다.
: <></>태그
✔ 키를 입력하지 않아도 에러가 나지 않음
✔ 여러개의 요소를 반환할 때 유용하게 사용됨
✔ 실제 돔에는 반영되지 않고 에러 나지 않고 반환할 수 있음
✔ {null}, {false} 조건부 출력 때 유용하게 사용
{ count.value === 0 && <Title title={
현재 카운트: ${count.value} />}