TIL

[TIL] Optional chaining ES11문법

youngble 2022. 2. 13. 06:10

 

자바스크립트 최신 문법들을 다시한번 훑어보면서 optional chaining 기능을 배웠는데 들으면서 번뜩 떠오른 부분이 있었고 이 최신 문법을 사용하여 예전 프로젝트를 수정하면 코드가 더 줄어들지 않을까 생각했던 부분이 있었다.

Optional Chaining?

The optional chaining operator (?.) enables you to read the value of a property located deep within a chain of connected objects without having to check that each reference in the chain is valid.

위는 MDN 에서 정의된 설명이다. 번역하자면 optional chaining(?.) 을 사용하여 해당 연계된 객체들안의  각각의 참조값이 유효한지를 체크를 하지않고도 그 속성값을 읽을수 있도록 해준다고 한다. 

어떤상황에서 사용되는지 설명해보면 우리가 객체안의 속성에 접근을 할때 .연산자를 사용한다. 

 

> user = {name: {first: "John", last: "Doe"}}
> user.name.first
'John'

하지만 만약에 내가 접근하고자하는 속성값이 아직 선언이 안되었거나 값이 없다면 TypeError가 발생한다.

user.address.street
Uncaught TypeError: Cannot read property 'street' of undefined

이럴때 만약 내가 선언 하지않았지만 나중에 존재한다면 접근을 하고 에러없이 실행하기위해서 쓰는게 optional chaining이다 말그대로 '부가적인 연계' 로 해당 속성이 있다면 연쇄작용하는 것이라고 생각하면 될거같다.

?.은 ?.'앞’의 평가 대상이 undefined 나 null인 경우에 TypeError 대신에 undefined를 얻게 된다. 결과가null이나undefined가 아닌 경우엔 값이 ‘있다’ 혹은 '존재한다’라고 표현

 

그렇다면 프로젝트에서 어떻게 사용할수있다는건가?

내가 왜 이걸 보면서 번뜩이면서 프로젝트를 수정해야겠다! 라고 생각한 부분이 있었는데 이제 실질적으로 내가 어떻게 활용했고 코드를 개선했는지 설명해 보도록하겠다.

프로젝트내에 있는 많은 컴포넌트중 하나로 마이페이지의 알람배너에 사용자가 설정한 값이 있을때 보여주는 컴포넌트이다.

알림 OFF 나 오후 1:00 라는 문자를 보여주기위해선 그전에 설정한 값을 DB에 요청을 보내 리덕스에 담아 리덕스 안에 있는 데이터들을 보여주는 형식이다.

마이페이지 useEffect부분 DB요청
리덕스에 담긴 notice데이터를 useSelector를 이용하여 가져오기

리액트 훅useEffect을 사용하여 모든 랜더링이 끝난 시점인 componentDidMount 에서 DB로 알림 데이터를 요청을해서 가져온다면 렌더링과정 중에는 userNotice.time 이라는 값이 없을것이다.

컴포넌트 랜더링 return부분에서 userNotice.time에 접근하고있다.

만약 해당 코드에서 userNotice.time을 지우고 삼항연산자를 쓰지않고 

userNotice.time.sleepChk 으로 접근을 한다면 다음과 같이 에러가 난다

TypeError

이를 방지하기위해 위의 코드처럼 userNotice.time있는지 없는지를 체크하여 있다면 sleepChk에 접근을 하고 없다면 "알림 OFF" 라는 임시적인 데이터를 사용하여 렌더링 처리하도록 한것이였다.

하지만 이렇게 중복되는 userNotice.time 를 반복적으로 쓴다면 가독성도 떨어지고 코드가 길어진다. 이를 활용한것이 바로 optional chaining 인것이다!. (예시로 알림배너 부분을 했지만 다른 수많은 컴포넌트에서 이런 삼항연산으로 객체 접근에 존재할때아닐때의 삼항연산자가 많이 존재한다. 이걸 다 바꾼다면 코드량은 현저하게 줄어들것이다.)

 

위의 코드를 다시한번 바꾼다면 아래와 같이 바꿀수 있다

{userNotice.time?.sleepChk === false && "알림 OFF"}
{userNotice.time?.sleepChk ? userNotice.time.timePA : null}

만약 userNotice.time 속성이 존재하거나 값을 가진다면 sleepChk에 접근하는것이다. 이를 실행해보면 TypeError사라지는것을 볼수있다.

위와같이 콘솔을 찍어보면 AlarmBanner컴포넌트의 17줄이 두번 실행되는걸 볼수있는데 첫번째는 DB에 요청하기 전의 리덕스에 있는 값을 불러온것이고 두번째가 DB요청 후의 리덕스에 있는 값을 불러온것이다. 만약 optional chaining을 쓰지 않았다면 첫번째 undefined라고 뜬 부분을 실행하지못하고 TypeError가 났을것이다. 이렇게 중복되는 코드를 줄이면서 기존의 코드를 바꾸지않고도 해당 자료가 생성될때에 접근할수있는 ?. (optional chaining) 를 사용해 보았다!

 

고려해야할상황

?.은 ?.왼쪽 평가대상이 없어도 괜찮은 경우에만 선택적으로 사용해야 함.

내가 현재 사용하는 값이 꼭 필요한 값이라면 나중의 에러나 데이터를 쉽게 찾기위해선 안쓰는것도 다시한번 고려할것.

현재 프로젝트는 작기도하고 중복을 피하고 직관적인 코드를 위해 쓰기로 결정했지만

꼭 있어야 하는 값인데 없는 경우에 ?.을 사용하면 프로그래밍 에러를 쉽게 찾을 수 없으므로 이런 상황을 만들지 않도록한다.

 

 

참고하면 좋은 사이트:

https://ko.javascript.info/optional-chaining

 

옵셔널 체이닝 '?.'

 

ko.javascript.info

 

'TIL' 카테고리의 다른 글

[TIL] node.js 이용 서버구축 하기  (0) 2022.02.18
[TIL] SQL, NoSQL  (0) 2022.02.18
[TIL] XML, JSX, Babel(바벨)  (0) 2022.02.15
[TIL] JSON  (0) 2022.02.11
[TIL] 중고나라 코딩테스트, 서류통과  (0) 2022.02.10