0. 조건부 렌더링과 초기 코드
리액트를 배울 때 state를 배우자마자 익혀야 할 것이 있습니다.
바로 "조건부 렌더링" (Conditional Rendering)입니다.
특정 값에 따라서 다른 컴포넌트를 그리고 싶을 때 사용하는 방법으로,
웹 상에서 여러 방법을 확인할 수 있습니다.
글을 작성할 기본 코드는 아래와 같습니다.
App.js
< 클래스형 컴포넌트 형태 >
import React, { Component } from "react";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true,
};
}
render() {
return (
<div className="App">
<h2>조건부 렌더링 예시입니다.</h2>
<div>
<button style={{margin: 10}}>Login</button>
</div>
<div>
<button style={{margin: 10}}>Logout</button>
</div>
</div>
);
}
}
export default App;
< 함수형 컴포넌트 형태 >
import React, { Component } from "react";
import "./App.css";
import { useState } from "react";
export const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(true);
return (
<div className="App">
<h2>조건부 렌더링 예시입니다.</h2>
<div>
<button style={{ margin: 10 }}>Login</button>
</div>
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
</div>
);
};
export default App;
state 저장이 전부이기 때문에 useState로 초기값을 저장하고 진행하시면 됩니다.
저는 Vite로 리액트 프로젝트를 빌드했으며,
초기화면은 다음과 같습니다.
이제 여기서 6가지 방법으로 조건부 렌더링을 해보려고 합니다.
해당 예시를 작성하기 전에
제가 했던 프로젝트 기준으로
조건부 렌더링의 몇 가지 예시를 들어드리겠습니다.
(1) 날짜를 입력받아 그 사람의 생일에 따른 결과물을 보여준다. ( 탄생 띠, 어울리는 탄생석, 무슨 세대인지 정의해 주기 등 )
(2) 특정 쿠키값을 읽었을 때 해당 값이 있는 경우에는 화면을 보여주고, 그렇지 않으면 보여주지 않는다.
(3) (지금 현재 예제) 로그인 됐을 때는 로그아웃 버튼을, 로그아웃이 된 상태에서는 로그인 버튼을 보여준다.
조건부 렌더링은 여러가지에 쓰일 수 있으며
대체로 useState를 통해 다음 state가 바뀌고 새로 렌더링 되면서 사용되곤 합니다.
이제 예시로 떠나봅시다.
1. if..else 문을 사용하기
가장 초보적인 방식입니다.
퍼포먼스가 좋지 않기 때문에 추천하지 않습니다.
이런 방식은 피하는게 좋습니다.
< 클래스형 컴포넌트 >
import React, { Component } from "react";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoggedIn: true,
};
}
render() {
let { isLoggedIn } = this.state;
console.log(isLoggedIn);
const authButton = () => {
if (isLoggedIn) {
return <button style={{ margin: 10 }}>Logout</button>;
} else {
return <button style={{ margin: 10 }}>Login</button>;
}
};
return (
<div className="App">
<h2>조건부 렌더링 예시 1번입니다.</h2>
{authButton()}
</div>
);
}
}
export default App;
< 함수형 컴포넌트 >
import React, { Component } from "react";
import "./App.css";
import { useState } from "react";
export const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(true);
if (isLoggedIn) {
return (
<>
<h2>조건부 렌더링 예시 1번입니다.</h2>
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
</>
);
} else {
return (
<>
<h2>조건부 렌더링 예시 1번입니다.</h2>
<div>
<button style={{ margin: 10 }}>Login</button>
</div>
</>
);
}
};
export default App;
혹은 컴포넌트를 다른 함수로 분리하면 이렇게 정리할 수 있습니다.
import React, { Component } from "react";
import "./App.css";
import { useState } from "react";
const AuthButton = (props) => {
const [isLoggedIn, setIsLoggedIn] = useState(props.isLoggedIn);
if (isLoggedIn) {
return (
<>
<h2>조건부 렌더링 예시 1번입니다.</h2>
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
</>
);
} else {
return (
<>
<h2>조건부 렌더링 예시 1번입니다.</h2>
<div>
<button style={{ margin: 10 }}>Login</button>
</div>
</>
);
}
};
const App = () => {
const isLoggedIn = true;
return <AuthButton isLoggedIn={isLoggedIn} />;
};
export default App;
결과물은 다음과 같습니다.
isLoggedIn의 값에 따라서 발생하는 버튼이 달라집니다.
2번부터는 함수형 컴포넌트로 정리해 보겠습니다.
2. switch 문을 사용하기
switch-case문을 이용하는 방법입니다.
2개 이상 (3개, 4개...)의 조건이 있을 때 유용한 방법입니다.
또한 특정 변수 내의 케이스를 뚜렷하게 볼 수 있기 때문에
가독성도 좋은 편입니다.
import React, { Component } from "react";
import "./App.css";
import { useState } from "react";
const AuthButton = (props) => {
const [isLoggedIn, setIsLoggedIn] = useState(props.isLoggedIn);
switch (isLoggedIn) {
case true:
return (
<>
<h2>조건부 렌더링 예시 2번입니다.</h2>
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
</>
);
case false:
return (
<>
<h2>조건부 렌더링 예시 2번입니다.</h2>
<div>
<button style={{ margin: 10 }}>Login</button>
</div>
</>
);
default:
return null;
}
};
const App = () => {
const isLoggedIn = true;
console.log("App >>", isLoggedIn);
return <AuthButton isLoggedIn={isLoggedIn} />;
};
export default App;
3. 요소 변수를 사용하기
요소 변수(Element variables)는 조건부 렌더링을 별도의 함수로 뽑아서 사용하는 것과 비슷합니다.
요소 변수란?
JSX Element를 가지고 있는 변수 (하단의 AuthButton)
import React from "react";
import "./App.css";
import { useState } from "react";
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(true);
let AuthButton;
if (isLoggedIn) {
AuthButton = (
<>
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
</>
);
} else {
AuthButton = (
<>
<div>
<button style={{ margin: 10 }}>Login</button>
</div>
</>
);
}
return (
<>
<h2>조건부 렌더링 예시 3번입니다.</h2>
{AuthButton}
</>
);
};
export default App;
이 경우에는 조건에 따라서 특정 변수가 JSX의 값을 할당받는 방식입니다.
아래와 같이 표현 결과가 그려집니다.
4. 삼항연산자 (Ternary Operators)
삼항연산자는 많은 조건부 렌더링 예시로 나오는 것 중에 하나입니다.
삼항연산자는 다음과 같이 사용합니다.
특정조건 ? true일 때의 표현식 : false일 때의 표현식
< 예제코드 >
import React from "react";
import "./App.css";
import { useState } from "react";
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(true);
return (
<>
<h2>조건부 렌더링 예시 4번입니다.</h2>
{isLoggedIn ? (
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
) : (
<div>
<button style={{ margin: 10 }}>Login</button>
</div>
)}
</>
);
};
export default App;
표현이 너무 길어져서 컴포넌트의 가독성이 현저히 떨어지는 경우
별도의 함수를 만들어서 해당 내용을 적으세요. (삼항연산자를 return 문에 표기)
5. 논리연산자 (&&)
&& 연산자는 하나의 조건이 참일 때, 실행되는 방식입니다.
import React from "react";
import "./App.css";
import { useState } from "react";
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(true);
return (
<>
<h2>조건부 렌더링 예시 5번입니다.</h2>
{isLoggedIn && (
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
)}
</>
);
};
export default App;
삼항연산자와 달리 특정 조건에 대한 참일 때 사용하는 문구입니다.
영어로 Short circuit evaluation이라고 합니다.
6. 즉시 실행되는 함수형 표현(IIEFs)
https://developer.mozilla.org/en-US/docs/Glossary/IIFE
IIFE는 글자 그대로 "선언되자마자 실행되는 함수"입니다.
신생아가 태어나자마자 어디에 저장되는 게 아니라 바로 뛰어버리는 것이죠.
추후 재사용하기 위해 저장해 두는 것이 아니라, 선언 즉시 그것을 실행해 버립니다.
이 방식은 해당 코드 내에 모든 자바스크립트 코드를 작성할 수 있기 때문에
JSX 방식으로 표기하지 않을 수 있다는 장점이 있습니다.
< 예제 코드 >
import React from "react";
import "./App.css";
import { useState } from "react";
const App = () => {
const [isLoggedIn, setIsLoggedIn] = useState(true);
return (
<>
<h2>조건부 렌더링 예시 6번(IIFE)입니다.</h2>
{(function () {
if (isLoggedIn) {
return (
<div>
<button style={{ margin: 10 }}>Logout</button>
</div>
);
} else {
<div>
<button style={{ margin: 10 }}>Login</button>
</div>;
}
})()}
</>
);
};
export default App;
또한 function이라는 키워드를 생략하고 다음과 같이 작성해도 됩니다.
{(() => {
if (isLoggedIn) {
return <button>Logout</button>;
} else {
return <button>Login</button>;
}
})()}
형태는 전체 괄호() 안에 함수가 들어가고, 전체 괄호를 빠져나와 다시 괄호를 한 쌍을 만듭니다.
( 함수(){} )() <--- 이렇게 생겼습니다.
참고할만한 글:
1. 조건부 렌더링에 대한 글 (클래스형 컴포넌트가 예시로 되어있음)
2. 조건부 렌더링 최적화하기
https://medium.com/@cowi4030/optimizing-conditional-rendering-in-react-3fee6b197a20
끝!