import { useState, useEffect } from "react"
function App() {
const [users, setUsers] = useState([])
useEffect(() => {
// Data Fetching -> Side Effect
fetch("http://test.com/users") // (1)
.then(res => res.json()) // (2)
.then(res => setUsers(res)) // (3)
}, [])
return (
<ul>
{users.map((user) => {
<li key={user.id}>{user.name ? "" : ""}</li>
})}
</ul>
)
}
위 코드는 가상API로부터 유저 목록을 받아오는 코드다. 데이터 호출은 side Effect에 해당하므로 useEffect안에서 사용해야 한다. 컴포넌트의 랜더링 과정을 차례로 보면 랜더링과 useEffect hook 사이의 관계를 봐야한다.
1.App 컴포넌트가 랜더링된다. 첫 랜더링이므로 state인 users의 값은 빈 배열이다. 그러므로 빈 ul이 브라우저에 출력된다.
<ul></ul>
// 받아온 데이터가 다음과 같은 형태라고 가정하자
[
{ id: "1", name: "React" },
{ id: "2", name: "Side Effect" },
{ id: "3", name: "useEffect" }
]
<ul>
<li key="1">React</li>
<li key="2">Side Effect</li>
<li key="3">useEffect</li>
</ul>
프로젝트를 진행하다보면 특정 조건에서만 컴포넌트를 랜더링해야 하는 상황이 발생한다.
컴포넌트 함수 내부에서 특정 값에 따라 선택적으로 랜더링하는 것을 조건부 랜더링(conditional rendering)이라고 한다.
import { useState, useEffect } from "react";
export default function App() {
const [data, setData] = useState({});
useEffect(() => {
fetch("/mock.json")
.then((res) => res.json())
.then((res) => setData(res));
}, []);
return (
<div className="App">
<h1>Hello useEffect!</h1>
<h2>조건부 렌더링 연습 문제</h2>
<ul>
{data.users.map((user) => {
return <li key={user.id}>{user.username}</li>;
})}
</ul>
</div>
);
}
이렇게만 쓰면 코드상에는 문제가 없지만 브라우저에서는 에러가 발생한다. 아아아아아아주 골치가 아프다 모니터 다 뿌수고싶다.
에러코드를 씹어보면
1. TypeError
타입에러라는 말이다. number 타입 데이터에 object 타입 데이터에만 할 수 있는 동작을 하는 등의 상황에 발생할 수 있는 에러다.
cannot read property 'map' of undefined
그대로 읽어보면, 말 그대로 undefined라는 값에 대하여 map함수를 실행하려 했다는 뜻이다. 허나 map함수는 배열 데이터에 속해 있는 메서드이다. 우리가 undefined.map()과 같은 형태로 코드를 작성하지 않았다면 볼 일이 없을 에러인것 같다.
data.users.map((msg) => {}}
에러 화면에서 볼 수 있듯 22번 줄에 커서가 있고, 그 부분의 문장을 보니 (2)에서 봤던 map 함수가 눈에 밟힌다. 그것은 data.users까지의 값이 undefined라는 뜻이다. ㅈㄴ답답하다 개빡친다
종합해보면
조건부 랜더링을 구현하려면 삼항 연산자나 &&연산자를 사용해야 될 수 있다.
⁉️ 차이점
웹사이트에 로그인 시 보유 포인트를 확인할 수 있는 코드를 구현한다고 가정하면
해당 컴포넌트는 부모 컴포넌트로부터 isLogin, name, point 라는 3가지 props를 전달받아서 isLogin의 상태가 true일 경우 사용자의 이름과 보유 포인트 내역을 출력한다.
function Greetin(props) {
const { isLogin, name, point } = props;
return {
<div>
{isLogin ? (
<div>
<p>{name}님 환영합니다!</p>
<p>현재 보유중인 포인트는 {point}원 입니다.</p>
</div>
) : null}
</div>
}
}
삼항연산자의 경우 false일 경우의 값을 반드시 할당해주어야 한다. 그래서 무의미한 Null을 입력해준다.
function Greetin(props) {
const { isLogin, name, point } = props;
return {
<div>
{isLogin && (
<div>
<p>{name}님 환영합니다!</p>
<p>현재 보유중인 포인트는 {point}원 입니다.</p>
</div>
)}
</div>
}
}
&& 연산자의 경우 true인 경우만 랜더링 하겠다는 것을 피력함과 동시에 null을 생략할 수 있어 가독성이 높아진다.