목록으로

React 조건부 렌더링

시리즈
2024. 11. 13. PM 2:44:25

조건부 렌더링

조건문도 구문이기에 JSX에서 사용할 수 없습니다

에서 살펴본 바와 같이 JSX에서 JavaScript 구문은 사용하지 못하지만, 표현식은 사용할 수 있습니다. 그래서 for문을 사용하는 대신 배열의 map() 메서드를 사용했는데요. 조건문도 사용하지 못해요.
이 코드는 허용되지 않는 거죠. 대체 왜 구문은 허용되지 않는 걸까요? 편에서 JSX를 사용하지 않고 리액트로 렌더링하여 뭔가를 출력했던 것 기억하시죠?
이 JavaScript를 JSX로 표현하면 다음과 같습니다.
JSX에서 style 정보를 객체(plain object)를 전달하는 표현식을 잘 보세요. 여기에 for문을 넣어볼까요?
이 JSX를 JavaScript로 변환하면 어떤 모양일까요?

JSX에서 표현식만 허용하는 이유

아마 이런 코드로 변환해야 할 거예요. 당연히 문법 오류가 발생하고요. 물론 이런 문법 오류는 대응할 수 있을 거예요. JSX는 JavaScript 코드로 변환(Transpiling)하는데, 저런 구문을 사용할 수 있게 적절히 처리하는 거죠. 그렇다면 대체 왜 번거롭게 구문은 제한하고 표현식은 허용하는 걸까요? 제가 예상하는 몇 가지 이유가 있습니다.
먼저 리액트는 선언형 프로그래밍을 지향해요. 선언형 프로그래밍은 뒤에서 설명해드릴게요. 표현식은 선언형 프로그래밍으로 UI를 표현하는 데 적합하지만, 코드 그 자체가 명령문이지 값을 생성하진 않는 구문은 선언형에 어울리지 않아요. 선언형의 대표격인 HTML엔 아예 구문이 없고, 엑셀, 또는 스프레드시트도 값을 다루거나 값을 반환하는 함수는 있지만 구문은 없지요.
두 번째 이유는 JSX에서 중괄호({})로 감싼 JavaScript 코드는 JSX를 JavaScript로 변환(Transpiling)하고 났을 때 React.createElement() 함수의 인자로 전달되어 코드 변환 패턴이 명료합니다. 하지만 구문은 함수의 인자로 전달할 수 없으며, 구문을 위한 별도 코드 분리와 실행 과정을 넣는다면 변환(Transpiling) 처리도 복잡하고, 보안 상 문제를 야기할 가능성이 커집니다.
프로그래밍 언어에 수준이 있다는 것 아시나요? 기계어에 가까울수록 저급 또는 저수준, 자연어에 가까울수록 고급 또는 고수준 언어라고 부릅니다. JavaScript나 Python 같은 언어는 고수준 언어지요. 왜 뜬금없이 언어 수준을 설명드리냐면요. 같은, 또는 비슷한 수준으로 언어를 변환하는 걸 Transpiling이라고 하고, 저수준 언어로 변환하는 걸 Compiling이라고 한다는 걸 설명드리기 위해서예요 대개 기계어나 바이트 코드로 변환하는 걸 Compiling이라고 하며, 이 과정에서 코드를 분석해 최적화 기법이 적용됩니다. 요즘엔 컴파일러가 워낙 발전해서 사람이 성능이 떨어지게 작성한 코드도 더 나은 성능을 발휘하도록 최적화하기도 하죠.
리액트 코드를 웹 브라우저에서 실행하려면 JavaScript로 변환해야 하는데, 이 변환 과정 대부분이 Transpiling입니다. 그런데 놀랍게도 Compiling 동작이 이뤄지는데 바로 최적화입니다. 이런 최적화를 하는 데 구문보다 표현식이 유리합니다. 코드를 정적 분석하기에 좋고, 나중에 다룰 메모이제이션을 적용하기에도 좋지요.

&& 구문과 삼항연산자 사용하기

JSX에서 구문은 사용할 수 없지만, 일부 구문은 사용 가능합니다. 구문과 표현식의 가장 큰 차이는 표현식은 값을 생성한다는 데 있는데요. 구문도 값을 생성하는 것처럼 동작하면 JSX에서 사용할 수 있습니다. 바로 && 구문이죠. 그리고 하나 더 있으니, 바로 삼항(ternary)연산자예요. 우리는 이 둘을 사용해 조건부 렌더링을 이미 해봤습니다.
App.jsx 파일에 있는 코드지요. 먼저 && 구문을 볼까요?
!!email은 풀어쓰자면 not not email입니다. email 변수에 값이 있어서 truthy하다고 가정하면 첫 번째 not으로 인해 false가 돼요. 그런데 그 결과에 다시 not이 붙어서 true가 되죠. 결과적으로 truthy를 true로 변환한 거예요.
재밌는 건 표현식의 일부인 연산자도 표현식으로 취급되어 값을 반환한다는 것입니다. 자, &&는 AND 연산입니다. AND 연산은 연산자 앞 뒤에 있는 값 모두가 truthy 해야 참(true)으로 평가돼요. 이 말은 && 앞이 참이라면 뒤에 있는 것까지도 true/false 또는 truthy/falsy를 따져봐야해요. && 연산자 위엔 JSX 코드가 있고, 이건 JavaScript로 변환했을 때 React DOM Element 객체입니다. &&연산자는 연산이 종료한 시점의 값을 반환하는데, !!email 코드가 참으로 평가되면 && 연산자 오른쪽에 있는 값, 즉, React DOM Element 객체가 반환되고, 결국 이 객체가 화면 렌더링에 사용됩니다. 그에 반해 !!email이 거짓으로 평가되면, && 연산자 오른쪽은 볼 것도 없이 거짓으로 평가되므로 false가 React 렌더링에 사용되는데, React는 false 값을 렌더링하지 않습니다. 결국 다음 JavaScript 코드와 같은 동작을 한 셈이지요.
앞서 편에서 “렌더링하지 않는 값” 절 내용을 기억하시나요? 숫자 0은 falsy 하지만 화면에 출력된다고 했지요? 0 && <p>puddingcamp</p> 이 코드에서 숫자 0은 falsy하므로 && 연산자 오른쪽은 평가하지 않아서 0을 반환하는데, 리액트는 falsy가 아니라 숫자 0이라는 값이므로 화면에 출력합니다. 그래서 저는 명시적으로 true/false 로 반환되도록 !!email과 같은 코드를 작성하지요.

삼항연산자

이 코드에 삼항연산자를 썼습니다.
&& 연산자를 썼다면 좀 장황해져요.
삼항연산자가 간단하죠? 하지만 가독성이 좋진 않아요. 조금 가독성 좋게 고쳐볼까요?
하지만 JSX가 조금만 복잡해져도 가독성이 떨어지고 문법 오류를 일으킬 여지도 커져요.
같은 동작을 && 연산자로 표현해보겠습니다.
음. 별 차이 없네요. 그러므로 상황에 맞춰 조금이라도 더 나은 표현을 쓰시길 바랍니다. 🙂

선언형 프로그래밍

선언형 프로그래밍은 프로그래밍 패러다임 중 하나로, “어떻게” 수행할지에 관심을 갖지 않고 “무엇을” 원하는지 관심을 갖는 방식이에요. 선언형 프로그래밍의 대표 언어가 바로 HTML이죠.
이 코드는 h1태그를 만들고 그 안에 “푸딩캠프” 텍스트를 넣으라고 코드로 명령하지 않아요. 단순히 “푸딩캠프 텍스트는 h1 제목이다”고 선언할 뿐입니다. 이번 편에서 또 등장하는 편을 보면 명령형과 선언형 모두 등장합니다. React.createElement()는 명령형으로 화면 렌더링을 하는 것이고, JSX는 선언형으로 화면 렌더링을 하는 것이죠. 선언형의 대표적인 또 다른 예시는 SQL, 그리고 스프레드시트가 있습니다.
선언형 프로그래밍은 다음 장점이 있어요.
  • 가독성이 좋다. React.createElement('h1', {}, '푸딩캠프') vs <h1>푸딩캠프</h1>
  • 유지보수성이 좋다. “무엇”을 할지만 정의하면 되므로, 내부 로직을 변경하기 용이하죠.
  • 병렬처리하기 좋다. 순서에 의존적이지 않으므로 병렬 실행하기 좋아요. 무슨 말이냐하면 3 * 2 + 4 / 2 이 계산은 계산 우선순위에 따라 뒤에서 계산될 식은 앞 식 결과가 나와야 하지만, 1 + 2 + 3 + 4 + 5 + 6 는 계산 순서가 상관 없으므로 1 + 2 + 34 + 5 + 6을 각각 두 사람이 맡아 계산한 뒤에 합쳐도 되지요.
리액트 뿐만 아니라 프론트엔드 프로그래밍, 더 나아가 UI 프로그래밍에선 이런 선언형 프로그래밍 패러다임을 주로 씁니다.
토이스토리 2기 모집 중!
푸딩캠프 뉴스레터를 구독하면 학습과 성장, 기술에 관해 요약된 컨텐츠를 매주 편하게 받아보실 수 있습니다.
목차