[React] Data Fetching & 조건부 랜더링

짱쫑·2021년 12월 7일
0
post-thumbnail

🐦 Data Fetching

::Data Fetching with useEffect Hook

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>
  1. 랜더링이 완료된 후 useEffect가 실행되고 첫 번째 인자로 받은 함수(callback)가 실행된다.
  • 2-1. (1)의 fetch() 함수는 첫 번재 인자로 데이터 요청을 보낼 url을 문자열로 받고, 두 번째 인자에는 데이터 요청에 대한 옵션을 객체로 넣는다.
  • 2-2. (2)는 앞선 요청에 응답이 정상적으로 돌아왔다면 응답의 body에 들어있는 데이터를 자바스크립트 객체 형태로 변환시킨다.
  • 2-3. (3)에서 해당 객체를 setUsers함수에 인자로 넣어 호출하여, users의 값을 업데이트 한다.
  1. 2-3에서 호출된 setState에 의해 state가 변경되고, 변경된 state를 반영한 새로운 화면을 그리기 위해 App 컴포넌트가 랜더링 된다. 이 때 state인 users는 여러 개의 객체를 담고 있는 배열의 형태이므로 JSX요소가 화면에 랜더링 된다.
// 받아온 데이터가 다음과 같은 형태라고 가정하자
[
	{ 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>

::Error Handling with Conditional Rendering

프로젝트를 진행하다보면 특정 조건에서만 컴포넌트를 랜더링해야 하는 상황이 발생한다.
컴포넌트 함수 내부에서 특정 값에 따라 선택적으로 랜더링하는 것을 조건부 랜더링(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 타입 데이터에만 할 수 있는 동작을 하는 등의 상황에 발생할 수 있는 에러다.

  1. cannot read property 'map' of undefined
    그대로 읽어보면, 말 그대로 undefined라는 값에 대하여 map함수를 실행하려 했다는 뜻이다. 허나 map함수는 배열 데이터에 속해 있는 메서드이다. 우리가 undefined.map()과 같은 형태로 코드를 작성하지 않았다면 볼 일이 없을 에러인것 같다.

  2. data.users.map((msg) => {}}
    에러 화면에서 볼 수 있듯 22번 줄에 커서가 있고, 그 부분의 문장을 보니 (2)에서 봤던 map 함수가 눈에 밟힌다. 그것은 data.users까지의 값이 undefined라는 뜻이다. ㅈㄴ답답하다 개빡친다

종합해보면

  • data.users가 배열 데이터일 것을 기대하고 map함수를 사용했다.
  • 근데 어느 시점에서 data.users는 undefined가 분명 어느 순간에는 비어있었다는 말이고, 상태값의 시점에 관한 문제라면 React의 랜더링 과정과 연관이 있을것이다.

::삼항 연산자 / 단축 평가

조건부 랜더링을 구현하려면 삼항 연산자나 &&연산자를 사용해야 될 수 있다.

⁉️ 차이점

  • 삼항 연산자의 경우는 조건의 true/false에 따라 각기 다른 UI를 랜더링 할 때 사용한다.
  • &&연산자의 경우 조건이 true일때만 특정 UI를 랜더링 하고 false일 때는 아무것도 랜더링 하지 않도록 할 때 사용한다.

웹사이트에 로그인 시 보유 포인트를 확인할 수 있는 코드를 구현한다고 가정하면
해당 컴포넌트는 부모 컴포넌트로부터 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을 생략할 수 있어 가독성이 높아진다.

‼️ && 연산자 사용시 주의사항

  • 변수가 숫자 타입인 경우 0은 false다.
  • 변수가 문자열 타입인 경우 빈 문자열 ""도 false다.
profile
不怕慢, 只怕站

0개의 댓글