-
[React] React에서 흔히 발생하는 실수 4가지front-end/React 2023. 5. 17. 14:04
이 포스팅은 제가 리액트로 개발 및 공부하면서 실제로 닥쳤던 이슈들이라서
유튜브에서 영상의 Reference를 참조 하였습니다.
출처 :
https://www.youtube.com/@LamaDev
https://www.youtube.com/@WebDevSimplifiedWeb Dev Simplified
Web Dev Simplified is all about teaching web development skills and techniques in an efficient and practical manner. If you are just getting started in web development Web Dev Simplified has all the tools you need to learn the newest and most popular techn
www.youtube.com
1.Common Mistake #1 / &&연산자를 쓸때 조심해야하는 것 중 한가지
리액트로 프론트 개발을 하다보면 "&&" 연산자로 첫번째 피연산자가 true 이면 두번째 피연산자가 true를 반환한다.
이를 통해서 아래와같이 코드를 짠적이 많을텐데요, 아래 코드는 arr의 length가 존재하면 Array items를 화면에 뿌려주는
간단한 예제 코드입니다. 지금은 arr 배열에 1,2,3이 담겨져 있어서 화면에 잘나오는걸 볼 수 있습니다.


Arr가 화면에 잘 나오는 이미지 하지만 아래의 코드 처럼 어떠한 이유로 arr의 값이 없어진다면 화면에 어떻게 나올까요?
화면에 보다시피 0이 출력이 됩니다. 제가 기대했던건 0이 출력이 되는게 아니라 화면에 아무것도 렌더링이 안되서
빈화면이 보이는걸 예상했습니다.


0 이출력 된 모습 jsx(tsx) 에선 undefined , null , false 는 화면에 렌더링이 되지않습니다. 이것을 제외한 모든것은 화면에 렌더링이 됩니다.
&& 기호를 사용할시에는 boolean 값을 항상 리턴을 하는 피연산자를 이용해야 합니다.
위와 같이arr.length && 이런식을 쓸시 0 이 리턴 되면서 화면에 렌더링이 안되는 대신 0 이 렌더링이 됩니다.
(boolean 값이 아니기 때문에)

arr.length 대신 arr.length !== 0 이런식으로 falsy한 값을 선언 해줘야합니다
이런식으로 사소한 에러를 발생을 방지할수있습니다.
혹은 다른 방법도 있습니다. 바로 !!연산자를 붙히는것입니다.
!!연산자의 간단하게 말하자면:
!!" 연산자는 논리 부정 연산자인 "!"을 두 번 사용하여 값의 불리언(Boolean) 상태를 명시적으로 변환하는 역할을 합니다.
이 연산자는 값에 대해 불리언 변환을 수행하고, 해당 값이 참인지(false가 아닌 값) 또는 거짓인지(false나 빈 값)를 판별합니다.
"!!" 연산자의 동작은 다음과 같습니다:
주어진 값이 false, 0, 빈 문자열(""), null, undefined, NaN인 경우: 값은 false로 변환됩니다.
주어진 값이 true, 0이 아닌 숫자, 비어 있지 않은 문자열, 객체, 배열 등 비어 있지 않은 값인 경우: 값은 true로 변환됩니다.
2.Common Mistake #2 / useState 훅을 쓸때 조심해야하는 것중 한가지
아마 이 useState 실수는 리액트의 관한 문서 및 블로그 포스트를 보신분들이라면 한번쯤은 봤을거라고 생각합니다.
저 역시 블로그 Reference을 참고해서 이런식으로 개발을 했지만 , 100% 이해하지 못한 상태에서 사용해서 다시한번 정리겸 포스팅을 하려고합니다.
아래의 코드는 버튼을 누르면 각 arr의 시작과 끝 부분에 push , unshifit 를 이용해 숫자 0을 추가 해주는 간단한 예제입니다.
잘못된 방법 #1


JavaScript에서 배열은 참조 타입입니다. useState 훅을 사용하여 상태 배열을 선언하면 해당 배열의 변경이 발생할 때 React는 변경된 상태를 감지하고 화면을 업데이트합니다.
두가지의 add 함수들을 보면 불변성을 유지 하고 있지 않습니다.
리액트를 조금이라도 해본사람은 알겠지만 무조건 불변성 유지를 시켜야합니다. (immutable)
리액트가 그 배열이 다르냐고 묻는다면 "아니 아직 전의 하나의 배열을 가르키고있어 그래서 화면이 바뀌질않아"
이 방법은 불변성을 유지하지 않으므로 React에서 상태 변경을 감지하지 못하고 화면을 갱신하지 않습니다.
console.log는 현재 코드 실행 시점의 변수 값을 출력하기 때문에, addFirstArr와 addLastArr 함수 내에서 arr 배열에 값을 추가한 후에 console.log(arr)가 실행되면 수정된 배열의 상태를 출력합니다.
잘못된 방법 #2


spread operator을 통해 불변성을 유지해주며 number 인자를 각 위치에 맞게 추가 해주었습니다.하지만 버튼을 눌러보면 화면에는 1,2,3,0 마지막 0만 추가가 되고 처음 0은 추가가 안되는 모습을 볼수있으며 , console에 찍은 arr 도 1,2,3 을 반환합니다.
spread operator로 arr를 복사를 해준뒤 , number 인자만 추가 해준것이다. conosle엔 arr를 찍고있으니 arr의 값 1,2,3 을 그대로 반환 하고있습니다.
화면에는 왜 마지막 0 만추가가 되냐면 지금 하나의 버튼으로 두개의 함수를 온클릭 이벤트 처리를 하고있는데, 클릭을 하면 사실 0,1,2,3 으로 바뀌지만 바뀜과 동시에 1,2,3,0으로 바로 바뀝니다.
리렌더링이 일어나기전에 두개의 이벤트가 한번에 일어나기 때문입니다.
하지만 밑에 함수는 setArr([...arr,number]) 는 ...arr의 값 그대로 추가 하기때문에 1,2,3,0 만 추가 되는것이다. 그래서 마지막 함수가 overwrite하는것 입니다
React의 상태 업데이트는 비동기적으로 처리되기 때문에 setArr 함수가 호출되면 상태의 변화가 즉시 반영되지 않습니다. 따라서 console.log(arr)이 실행될 때는 이전의 arr 값을 출력하게 됩니다.

올바른 방법

useState의 setter함수에 current state 혹은 previous state를 콜백인자로 갖고올수있기때문에 , 리액트에서는 무슨일 있더라도 state를 직접 변경 하지말고 current state로 state 변경을 해줘야합니다.
두번째 함수로도도 이제 0이 붙는걸 볼 수 있습니다.
prev 의 인자를 갖고와서 (여기서 prev의 인자값은 0,1,2,3 이다. 왜냐하면 앞서 말했다시피 prev는 가장 최신의 업데이트 된 state를 갖고있기때문에 이제 0,1,2,3인 state에서 뒤에 0이 붙는다.)
설명: useState 훅의 setter 함수는 이전 상태 값을 콜백 인자로 받을 수 있습니다.
따라서 세 번째 방법은 이전 상태 값을 활용하여 새로운 배열을 생성하고 업데이트합니다.
이 방법은 불변성을 유지하며 React에서 상태 변경을 정확하게 감지하여 화면을 갱신합니다
결론: useState 의 Setter함수를 이용해 state를 건드릴때는 currentState의 콜백인자를 이용해서 수정해야합니다.
3.Common Mistkae #3 / useEffect와 useMemo 잘 이용하기


위 코드는 name,age,darkmode 라는 state를 갖고있고 , person의 객체가 변경이 있을때만 , useEffect의 console.log(person) 이
출력 되게 합니다.
그리고 체크박스로 다크모드로 변경할 수 있는 간단한 예제입니다.
age,name을 input 으로 업데이트 할때마다 콘솔창에 잘 출력되는것을 볼 수 있습니다.
useEffect의 Dependency에 darkMode 가 없음에도 불구하고, 여기서 다크모드 제어를 위해 체크를 해도 콘솔창의 person이 출력되는것을 볼수있습니다.

리액트는 Virtual DOM을 사용하여 화면을 업데이트하고, 상태 변화에 따라 새로운 Virtual DOM을 생성합니다. 이때, 상태 객체의 값이 변경되었다면 해당 상태를 참조하는 모든 객체도 새로 생성됩니다. 이는 불변성(Immutability)을 유지하기 위한 원칙 중 하나입니다.
여기서 person 객체는 name과 age 값을 속성으로 갖는 JavaScript 객체입니다. name과 age는 상태 변수로 선언되어 사용자 입력에 따라 변경될 수 있습니다.
코드에서는 렌더링이 될때마다 person 객체가 항상 새로운 객체로 간주됩니다.
즉, name과 age 값이 변경될 때마다 새로운 { name, age } 객체가 생성되는 것입니다.
예를 들어, 초기에 name이 "John"이고 age가 25인 경우, person 객체는 { name: "John", age: 25 }가 됩니다. 그리고 name이 "Alice"로 변경되면 person 객체는 새로운 객체 { name: "Alice", age: 25 }로 간주됩니다. 이후에 age가 30으로 변경되면 person 객체는 또 다른 새로운 객체 { name: "Alice", age: 30 }로 간주됩니다.
따라서, person 객체는 값이 같더라도 새로운 객체로 취급되기 때문에 useEffect의 의존성 배열에 person을 넣으면 name이나 age 값이 변경될 때마다 useEffect가 실행되는 것입니다. 이는 불필요한 콘솔 출력을 초래할 수 있습니다.

위 코드에서 useMemo 훅은 의존성 배열로 [name, age]를 가지고 있습니다. 즉, name과 age 값이 변경될 때만 person 객체를 재계산합니다.
처음 렌더링되었을 때와 name 또는 age가 변경될 때만 useMemo 콜백 함수가 실행됩니다. 그리고 person 객체는 이전에 계산된 값을 재사용합니다. 이전에 계산된 person 객체는 메모리에 저장되어 불필요한 계산을 피하고 성능을 향상시킵니다.
따라서, useMemo를 사용하면 person 객체가 항상 새로운 객체가 되는 문제를 해결하고, 의존성이 변경될 때만 계산을 수행하여 불필요한 연산을 방지할 수 있습니다.
리액트에서 객체(Object)나 배열(Array)과 같은 참조 타입의 변수를 useEffect의 의존성(Dependency)으로 사용할 때에는 useMemo를 사용하여 메모이제이션(Memoization)을 적용해야 합니다. 이렇게 함으로써 useEffect 내에서 의존성 배열의 값이 변경되지 않았을 때에는 이전에 계산된 값을 재사용할 수 있습니다.
요약하자면, 객체나 배열을 의존성으로 가지는 useEffect에서는 useMemo로 변수를 감싸주어 메모이제이션을 적용하고, 의존성 배열에는 useMemo로 감싼 변수들만 포함시키면 됩니다. 이렇게 함으로써 리렌더링이 발생할 때마다 동일한 객체가 새로 생성되는 현상을 방지할 수 있습니다.
4.Common Mistkae #4 / 객체 혹은 배열의 값을 수정할때


user state 안에 name,age,hasCar 이라는 객체를 담고 있고, User의 정보를 보여주고 , name을 바꿀 수 있는 인풋과 버튼이 있는
간단한 예제 입니다.
(as any 는 타입스크립트를 이용중이라 타입에러를 반환하기때문에 any로 선언하였습니다. 아마 jsx 를 이용하시면 에러가 안생기실겁니다 . ) -사실 여기서도 타입스크립트 이점이 드러나네요.
여기서 위 코드처럼 setUser 을 통해 user name을 바꾸면 객체가 아닌 string이 반환 되면서 원하는 결과를 얻지못합니다.
콘솔창을 보면 , "이름바꾼거" 라고 객체가 아닌 string이 반환이되죠 . 화면에서도 역시나 저희가 원하는 결과를 얻지못했습니다.

사실 이건 리액트의 특별만 문법이 아닌 자바스크립트를 잘 알고계시다면 왜 이렇게 출력이 되는지 알것같습니다.
아래와 코드처럼 말이죠.

onSubmit 함수를 아래와 수정하면 저희가 기대하던 결과를 얻을 수 있을겁니다.
실제로 저는 프로젝트를 하면서 API get 한 정보들을 프론트에서 바꿔줘야 할 상황이 굉장히 많았는데 , 이런식으로 처리하는일이 많았습니다.


마치며,
복습과 정리겸 포스트 작성을 해봤습니다.
위에 유튜브 링크들은 제가 애용하는 유튜버 두분입니다. 영어가 잘 안되시더라도 , 코드를 보면서 자막 키고 보시면 이해가 잘 될것같습니다.
리액트 개발을 하다보면 결국엔 자바스크립트를 잘하고 , 잘 파악 하고있으면 에러들의 이유를 금방 알아챌것 같습니다.
자바스크립트의 순 동작 원리 , 데이터 타입 등을 더욱 자세히 공부하면서 리액트 개발을 하면 품질이 좋은 코드를 작성할수있을거같습니다.
프론트엔드는 변화가 굉장히 빠른것같습니다. 하지만 자바스크립트를 탄탄히 한다면 새로운 프론트 프레임워크가 오더라도 수월하게 파악할 수 있을거같습니다.
---- 결국엔 자바스크립트입니다. ----
'front-end > React' 카테고리의 다른 글
[React]When to use UseMemo and useCallback (feat:memo) / useCallback 편 (0) 2023.08.09 [React validation] Zod vs Yup 비교 / react-hook-form 같이 쓰기 (0) 2023.06.05 [React] React query 개념 및 예제 (0) 2023.04.28 [React-Router V6] useOutletContext (0) 2023.01.13 [React-Router V6 ] Outlet , createBrowersRouter (0) 2023.01.13