오늘의 작업(회원 가입 페이지)

https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file

AllowJs: true를
AllowJs: false로 바꾸니 해결됐다.

자세한 내용은 해당 링크를 참고.

오늘은 팀원이 작업한 것을 내가 맡게 됐다.

회원 가입 창에서 이메일, 비밀번호가 형식에 올바르지 않으면 페이지에서 바로 피드백을 주고 싶다.

이러한 것을 마이크로 인터랙션이라고 한다.
마이크로 인터랙션이란 말 그대로 아주 세세한 단위의 상호작용이다.

회원 가입 버튼을 눌렀을 때 "형식이 맞지 않습니다."라는 알림창을 띄우는 것보다, 버튼을 누르기 전에 미리 알려주면 유저는 보다 더 편리한 사용 경험을 얻는다.

작업을 해보자.

기존 코드다.

우선 기본 형태만 보이도록 변경.

해당 양식을 검사하는 코드를 만들자.

input이 들어오면 해당 input이 어느 타겟에서 이뤄졌는지 switch문으로 검사한다.

  • 해당 타겟마다 input값을 변경하는 set함수
  • input값이 양식에 맞는지 검사하는 check함수

두 가지를 같은 level에서 실행시킨다.

양식을 검사하는 정규식

우선 콘솔로그로 간단히 확인해보자.

잘 된다.

maxLength도 추가했다.
최대 20글자까지만 입력하라고 제한하는 것.

불현듯 콘솔창을 보니 역시나 뭔가 있다.
나는 개발할 때 여백의 미를 가장 중요시한다.
해결해보자.

"password가 form 안에 들어있지 않습니다."

form 태그로 감싸라는 얘기다.

하나를 해결하면 또 하나가 따라오는 게 개발 과정.

"Input 엘리먼트에는 자동완성 속성(autocomplete)을 주세요."

autocomplete="new-password"는 새로운 비밀번호, 비밀번호 확인 input에 집어넣길 권장되는 속성이다.

그 외에도 여러 속성이 있는데 MDN을 참고하자.

전부 지정해주면 해결된다.

validateDOMNesting에러가 떴다.
영어를 해석하면 DOM 중첩 구조를 확인하라는 얘기 같다.

"div 태그는 p 태그의 자손으로 지정 못합니다."

p태그 안에 div태그를 넣어서 발생한 문제로 보인다.
해당 에러가 뜬 곳을 확인하자.

실제로도 p 태그 안에 div 태그가 삽입된 상태였다.
p 대신 div로 적용해서 해결했다.

이제 콘솔 말고 경고문구를 화면에 띄워보자.

우선 경고 메시지를 띄우는 컴포넌트를 분리해서 만들었다.

아까의 컴포넌트에서 내가 보고 싶은 것은 "회원 가입 양식"이지, 에러 처리를 보고 싶은 건 아니기 때문이다.

인풋에 글자 입력했더니 무한 렌더링이 발생했다.

해당 에러 검색

I suspect that the problem lies in the fact that you are calling your state setter immediately inside the function component body, which forces React to re-invoke your function again, with the same props, which ends up calling the state setter again, which triggers React to call your function again.... and so on.
함수 컴포넌트 내부에서 setState를 바로 부르기 때문에 발생하는 문제로 보이네요.
리액트가 같은 컴포넌트를 부르고, 같은 props를 가져오고, 같은 setState를 부르고, 다시 함수 호출을 반복하고...

이렇게, 컴포넌트 내부에서 바로 setState를 실시하면 똑같은 에러가 난다. 무한 렌더링 현상.

리액트에서 무한 렌더링을 유발하는 3가지

해당 링크를 먼저 참고하자.

If you update the state directly inside your render method or a body of a functional component, it will cause an infinite loop.
클래스형 컴포넌트의 render, 혹은 함수형 컴포넌트 내부에서 직접 setState를 쓰면 무한 루프에 빠질 수 있습니다.

State updates → triggers re-render → state updates → triggers re-render → …

Do you want to update a state only one time when the component mounts? Use useEffect with an empty array as a dependency.
컴포넌트가 생성(mount)될 때만 state를 업데이트하고 싶다면 useEffect를 사용하세요.

useEffect를 써도 뭔가 에러가 난다.
살펴보자.

React Hook useEffect contains a call to 'setMessage'. Without a list of dependencies, this can lead to an infinite chain of updates. To fix this, pass [target, status] as a second argument to the useEffect Hook.
리액트훅 useEffect에서 'setMessage'를 부르는 문구를 포함하고 있습니다. 의존성 없이 이렇게 작성하면 무한 업데이트 현상이 발생할 수 있습니다.
이를 방지하려면 [target, status]를 useEffect의 두 번째 인자로 넘겨주세요.

useState, useEffect로 무한 리렌더링 방지

Changing state will always cause a re-render. By default, useEffect always runs after render has run. This means if you don't include a dependency array when using useEffect to fetch data, and use useState to display it, you will always trigger another render after useEffect runs.
Unless you provide useEffect a dependency array.
state 변경은 항.상. 리렌더링을 유발합니다.
useEffect는 항.상. 렌더가 끝난 뒤에 실행되고요.
이게 뭘 뜻하냐면, 만약 useEffect로 데이터를 가져올 때 의존성 배열을 안 쓰고 useState도 쓰고 있다면, useEffect가 끝난 뒤에도 또 렌더링이 일어날 겁니다.
useEffect에 의존성 배열을 집어넣지 않는 이상, 계속.

말끔하게 해결됐다.

리액트 생명 주기 다이어그램

useEffect를 컴포넌트 내부에서 선언하는 이유는 그래야 props, state에 접근할 수 있기 때문이다.

useEffect는 함수형 컴포넌트 내부의 함수라고 볼 수 있다. js에서 함수 내부에서 함수를 쓴다는 건 클로저가 생성된다는 이야기이다.

렌더링이 끝나고 컴포넌트 생명 주기가 끝나도 useEffect는 컴포넌트 스코프에 있는 것들을 사용할 수 있는 것.

다만 useEffect는 렌더링할 때마다 매번 새로운 effect로 교체된다고 한다.

해결은 됐지만 에러가 뜰 때마다 위아래로 왔다갔다하는 게 보기 좋지는 않다. 적당한 여유 공간을 미리 주는 게 낫겠다.

적당해진 것 같다.

문제가 남아있다. 렌더링이다.
위 짤에서 봤겠지만 input 하나 입력할 때마다 뭔가 굉장히 깜빡인다.

에러가 없어도 렌더링이 엄청 된다.

언제 memo를 쓸 것인가

같은 props로 변경이 자주 일어나는 상황이면 memo를 권하는 듯하다.

에러 메시지 컴포넌트는 해결됐다.

추가로 모든 입력이 정상적으로 들어올 때에만 버튼이 클릭 가능하도록 변경했다.

오늘은 여기까지 하고 적당히 마무리.

좋은 웹페이지 즐겨찾기