이번 프로젝트 기간 동안 작업 도중 몇 가지 에러 문제를 봉착하였다.
해당 에러 문제에 관해 정리 및 해결했던 방안에 대해 정리해볼 기회가 필요할거 글을 써본다.
에러 로그 list는 아래와 같다.
svg의 path 영역만큼 주황색 hover 효과를 주었다.
그러나 svg의 TEXT는 절대 좌표로 위치 잡은 관계로 path 영역에 속박되지 않아 해당 텍스트
에 커서를 대면 path 영역의 주황색 hover 효과가 일어나지 않는 것을 볼 수가 있다.
svg를 이렇게 전문적으로 다뤄본 적이 없어서 문제를 해결하기 위해 별의별 CSS 효과를 다주어도
여전히 TEXT는 path 영역에 hover 효과를 주지 못하였다.
검색을 하여도 해당 문제를 알려주는 글이 없어서 이번에 처음으로 Stack overflow를 사용하여 현 문제에 관해 게시글을 올렸다.
그 결과 2시간도 안 지나서 답변이 왔으며 바로 해결되었다... 😨
pointer-events: none;
pointer-events
HTML 요소들의 마우스 커서/터치 event들(CSS hover/active, JS click/tap, 커서 드래그등)의 응답을 제어할 수 있는 속성이다.
pointer-events
에 none
속성을 줄 경우 HTML 요소에 정의된 클릭, 상태(hover,active등), 커서 옵션들이 비활성화되어 아래 gif 사진처럼 성공하였다.
많은 시간을 소비하며 삽질을 했는데, 해결책이 고작 CSS 속성 하나였다는 점에서 너무 어이가 없었지만,,, 이번 에러를 통해 CSS를 내가 좀 더 많이 알고 있어야 겠다는 점을 느꼈다.
모든 페이지마다 Header 부분의 로그인, 회원가입, 검색은 모달창으로 제작하였다.
그러므로 페이지 영역이 아닌 관계로 새로고침 효과가 일어나지 않는다.
만약 input 태그에 글을 작성 후 그대로 모달을 닫을 경우, 다시 해당 모달을 열면 그대로 전에 작성한 글들이 남아 있는 에러를 찾았다.
해당 에러를 해결하기 위해 DOM으로 접근하여 조치하였다.
const inputElement = document.querySelectorAll(".login_input");
inputElement.forEach((el) => {
el.value = "";
});
이메일, 패스워드 input 태그들은 모두 className이 login_input으로 이루어져 querySelectorAll
Document 메서드를 사용하였다.
각 input 엘리먼트의 text 글들은 value
속성에 해당되어 만일 모달 닫기 버튼을 누를 경우 공백 ""
으로 처리하도록 설정하였다.
결과 아래와 같이 input text들이 초기화되는데 성공하였다.
위에 소개한 input 초기화와 비슷한 문제이다.
그러나 input 태그의 text들은 해당 방법처럼 DOM으로 처리하면 해결되지만,
text 결과에 대한 메세지 text들은 자식 컴포넌트로 분리되어 DOM방식이 아니 함수로 초기화
처리를 하여야만 한다.
메세지 초기화를 하기위해서 2가지 대안책을 구했다.
아오 ㅋ 고민할 필요 있어? 그냥 컴포넌트를 이사시키면 되지~!!
윗 짤과 비슷한 상황처럼 자식 컴포넌트를 통쨰로 부모 컴포넌트로 이동시키면 된다.
이 방법을 쓰면 코드 로직을 심도있게 생각할 필요가 없으므로 편하다.
그러나 컴포넌트를 통째로 이동시키기에 3가지 문제가 있었다.
1. 비효율적인 작업 소요 시간
만일하여 자식 컴포넌트를 이동시키다 몇 개의 코드를 놓칠 경우 다시 되돌려야하는 경우가 발생할 수 있다. 그러기에 다시 되돌리는 과정에서 비효율적인 작업 시간이 소요된다.
2. 더욱 복잡해지는 부모 컴포넌트 코드
결국 컴포넌트가 합치게 되면, 부모 컴포넌트가 매우 복잡해진다. 컴포넌트라는 존재 자체가 복잡화된 코드를 좀 더 간결하게 처리하기 위해 등장하였다. 그러나 이 방법은 간결해지긴 커녕 오히려 지저분한 코드가 되므로 Anti Pattern이 된다.
3. 문제 회피하는 개발자답지 못한 행동
이 방법은 문제를 해결하는 쪽보다 회피할려는 좋지 못한 행동이므로 개발자로서 좋지 못한 마인드이다.
대안책 1번은 좋지 못한 방법이라는 판단이 들어, 사용하지 않기로 결심하였다.
부모 컴포넌트의 props를 자식 컴포넌트에 전달 후 props 참조하여 함수를 실행하게 만든다.
말로 설명하기에 이해가 안갈수도 있기에 메커니즘 원리 및 코드 구현으로 소개하겠다.
일단 해당 방법을 앞서 소개하기에 이번에 처음 배워 활용하는 hook인 useRef
, useImperativeHandle
부터 잠시 소개하고 넘어 가겠다.
함수형에서는 useRef
, 클래스형에서는 createRef
를 사용
Ref는 reference의 축약어로 Dom을 참조하여 ref를 제공
리렌더링을 방지
부모가 직접 접근하는 방식과 달리 자식 컴포넌트에서 활용할 수 있게 커스텀 마이징 역할을 수행한다.
먼저 부모 컴포넌트에서는 두가지의 useRef() 호출문을 선언한 후 자식 컴포넌트에 props로 전달한다.
동시에 부모 컴포넌트에서 current 프로퍼티를 활용하여 미리 호출할 자식 컴포넌트 함수 또한 선언한다.
전달 받은 props는 포워드Ref로 부르며 그대로 자식 컴포넌트에서 함수들을 호출할 때 참조하는 역할을 수행한다.
결국 useImperativeHandle을 통해 호출된 자식 컴포넌트의 함수는 부모 컴포넌트에 의존한다고 볼 수 있게 된다
const emptyNickname = useRef();
const emptyPw = useRef();
EmptyNickname과 emptyPw를 useRef hook
에 선언한다.
emptyNickname.current.emptyNickname();
emptyPw.current.emptyPw();
current
프로퍼티를 통해 미리 자식 컴포넌트 함수를 호출하도록 한다.
<Password_chan childRef={emptyPw} />
<Nickname_chan childRef={emptyNickname} />
useRef를 선언한 변수들을 각각 childRef
props에 담아 자식 컴포넌트에 전달한다.
useImperativeHandle(props.childRef, () => ({
emptyNickname() {
},
}));
useImperativeHandle(props.childRef, () => ({
emptyPw() {
},
}));
자식 컴포넌트는 useImperativeHandle를 활용하여 childRef
props를 참조 후 각 함수 안에 호출시키고 싶은 요소들을 넣어두기만 하면 된다.
즉, 모달 닫기 버튼을 누를 경우, .current
프로퍼티에 미리 호출한 함수들이 실행되면 덩달아 자식 컴포넌트의 함수들이 useImperativeHandle hook으로 인해서 실행되는 셈이다.
해당 방법을 활용하면 아래와 같은 useState 변수에 담긴 메세지들이 초기화된 결과를 볼 수가 있다.