📚 조건(삼항)연산자
조건(삼항)연산자는 JavaScript에서 세 개의 피연산자를 받는 유일한 연산자이다.
앞에서부터 조건문, 물음표(?), 조건문이 참(truthy)일 경우 실행할 표현식, 콜론(:), 조건문이 거짓(falsy)일 경우 실행할 표현식이 배치된다.
해당 연산자는 if...else문의 대체재로 빈번히 사용된다.function getFee(isMember) { return (isMember ? '$2.00' : '$10.00'); } // console.log(getFee(true)); // Expected output: "$2.00" // console.log(getFee(false)); // Expected output: "$10.00" // console.log(getFee(null)); // Expected output: "$10.00"
만약 filteredExpenses의 배열에 아무것도 들어있지 않을 때, 다른 컨텐츠를 출력하려면 어떻게 하면 될까?
조건식은 삼항연산자를 이용하여 구현할 수 있다.
return (
{filteredExpenses.length === 0 ? (
<div>지출한 비용이 없습니다.</div>
) : (
filteredExpenses.map((expenses) => (
<ExpenseItem]
key={expenses.id}
id={expenses.id}
title={expenses.title}
amount={expenses.amount}
date={expenses.date}
/>
))
)}
);
그런데 이렇게 긴 조건 표현식은 읽기 어려울 수 있다.
그럴 때 JS의 논리연산자를 사용할 수도 있다.
📚 논리적 AND (&&) (논리적 연결) 연산자
앤드연산자는 모든 불리언 피연산자가 true가 되었을 때 해당 피연산자의 집합은 true가 된다.
- 보다 일반적으로 왼쪽에서 오른쪽으로 평가할 때 연산자는 처음으로 만나는 거짓 같은 피연산자의 값을 반환한다. 혹은 모두 참 같은 값이라면 마지막 피연산자의 값을 반환한다.
- AND 연산자는 불리언이 아닌 값을 보존하고 다음과 같이 반환한다.
result = '' && 'foo'; // result 에 ""(빈 문자열)이 할당된다. result = 2 && 0; // result 에 0 이 할당된다. result = 'foo' && 4; // result 에 4 가 할당된다.
- 논리적 AND 표현식은 단락(short-circuit, 혹은 단축) 연산자이다.
각 피연산자는 불리언으로 변환되므로, 어떤 변환이 false로 판별되면 AND 연산자는 그 즉시 멈추고 거짓으로 판별된 피연산자의 원래의 값을 반환한다. 나머지 피연산자는 평가하지 않는다.(some falsy expression) && expr //첫 번째 피연산자 (some falsy expression)은 거짓 같은 값으로 평가되기 때문에, expr 부분은 절대 평가되지 않는다. // 만약 expr이 함수라면 해당 함수는 절대 실행되지 않는다.
이렇게 사용할 수 있다.
{filteredExpenses.length === 0 && <div>지출한 비용이 없습니다.</div>}
filteredExpenses.length === 0
가 true인 경우
AND 연산자는 불리언이 아닌 값을 보존하고 반환한다. 따라서 첫번째 피연산자의 조건에 만족하면 앤드 연산자 다음 부분으로 이동하여 그 값인 JSX <div>지출한 비용이 없습니다.</div>
를 반환한다. 즉, 필터링된 배열에 아무것도 들어있지 않은 경우 지출한 비용이 없다고 적힌 JSX를 반환된다.
filteredExpenses.length === 0
가 false 경우
AND 표현식은 단락 연산자이기 때문에 첫번째 피연산자가 false로 판별되면 그 즉시 멈추고 나머지 피연산자는 평가하지 않는다. 즉, 필터링된 배열에 요소가 들어있다면 지출한 비용이 없다고 적힌 JSX는 반환되지 않는다.
이처럼 삼항연산자 표현식 대신 &&연산자를 사용하여 구현할 수도 있다.
{filteredExpenses.length === 0 && <div>지출한 비용이 없습니다.</div>}
//마찬가지! 필터링된 배열에 요소가 있을 때만 ExpenseItem을 렌더링하도록 표현식 작성
{filteredExpenses.length > 0 &&
filteredExpenses.map((expenses) => (
<ExpenseItem
key={expenses.id}
id={expenses.id}
title={expenses.title}
amount={expenses.amount}
date={expenses.date}
/>
))}
하지만 이 코드도 JSX코드에 적기에는 과한 것 같다!
기존 JSX에 있던 로직을 변수로 만들어 컴포넌트 함수 자체로 끌어올려보자.
JSX 내부에서는 간단하게 동적 표현식을 추가하여 변수를 가리키면 된다.
그러면 가독성도 좋고, JSX 부분을 클린하게 유지할 수 있다.
import Card from "../UI/Card";
import "./Expenses.css";
import ExpenseItem from "./ExpenseItem";
import ExpensesFilter from "./ExpensesFilter";
import { useState } from "react";
const Expenses = (props) => {
const [filteredYear, setFilteredYear] = useState("2020");
const filterChangedYearHandler = (selectedYear) => {
setFilteredYear(selectedYear);
};
const filteredExpenses = props.items.filter(
(expense) => expense.date.getFullYear().toString() === filteredYear
);
//🔥 변수에 JSX 컨텐츠를 기본값으로 할당 및 저장할 수 있다.
let expenseContent = <div>지출한 비용이 없습니다.</div>;
//🔥 if문으로 체크
if (filteredExpenses.length > 0) {
//🔥 필터링된 배열에 요소가 있으면 ExpenseItem 컴포넌트를 매핑하는 로직으로 expenseContent를 오버라이드한다.
expenseContent = filteredExpenses.map((expenses) => (
<ExpenseItem
key={expenses.id}
id={expenses.id}
title={expenses.title}
amount={expenses.amount}
date={expenses.date}
/>
));
}
return (
<Card className="expenses">
<ExpensesFilter
onChangeFilterYear={filterChangedYearHandler}
selected={filteredYear}
/>
//🔥 JSX 내부에서는 간단하게 동적 표현식을 추가하여 expenseContent를 가리키면 된다.
{expenseContent}
</Card>
);
};
export default Expenses;
어떤 접근방법을 사용하든 상관 없지만, 가장 깔끔한 방법을 선택하자!
JSX 코드가 깔끔한게 좋으니 마지막 방법으로 고고~