짧은 지식은 문제를 키우고.. : forwardRef()

Jisu Park·2022년 12월 9일
0

오늘의개발일지-TIL

목록 보기
11/12
post-thumbnail

문제상황 🤯

??? : 입력값이 잘못되었는 데도 저장 버튼이 활성화되네용! 한 번 버튼이 활동화 되고 나면, 입력값을 이상하게 바꿔도 비활성화로 돌아가지 않는 것 같아요! 🤔

길고도 길었던 문제를 드디어 해결했다 생각하고 좀 개운해지던 찰나에 들어온 피드백.. 눈물을 머금고 다시 고쳐보려고 했는데,,,,

결론적으로 해결은 안 났다.. 하지만 오늘 찾은 것들을 적지 않고 넘어간다면, 다음주 이 문제를 해결해야 하는 나는 다시 처음부터 삽질을 해야하기에, 적어도 어디까지 삽질했는지는 적어보려고 한다.

배운 것들 🧐

문제의 시작

문제가 발생한 이유를 알아내는 것부터가 일의 시작이었는데, 가장 먼저 한 일이 부모 컴포넌트에 있는 useEffect가 입력창(자식 컴포넌트에 존재)의 값이 변할 때마다 불러와지는 지 확인하는 것이었다.
정말 여러 번 시도했지만, 입력창이 포커싱되었을 때를 제외하고는 - 심지어 그것도 불규칙적이었지만 - 입력창의 값이 바뀔때는 useEffect 내부의 로직이 작동하지 않는 다는 것을 확인했다.
이게 ref 값만의 문제인지 아님 useEffect 자체인지의 문제는 쉽게 파악할 수 있었는데, useEffect dependency로 명시된 변수들 중 부모 컴포넌트에서 선언된 state 값의 경우, 변경될 때마다 useEffect가 제대로 실행되는 것을 확인할 수 있었다.
그럼 문제의 시작은 ref나 forwardRef다. 여기서부터 나는 구글링을 시작했다.

useRef()의 특성

ref 값이 변화해도 리렌더되지 않는 컴포넌트

useRef가 반환하는 객체의 current 프로퍼티에 담긴 값의 상태가 바뀌어도 컴포넌트는 리렌더되지 않는다.

useEffect()에서 dependency로 ref값만 넣으면 변화를 감지 못한다고만 알고 있어서 필자의 경우에는 ref의 current 값까지 포함하여 dependency에 추가했었다. 그런데 알고보니 current 프로퍼티의 값이 변경되어도 컴포넌트는 리렌더 되지 않는다니, 문제의 원인을 제대로 짚고 넘어가게 된 셈이다. 더불어 나의 짧은 지식도 한 번 더 확인하고..ㅎ

ref 한 번 더 짚고 넘어가기

여기까지 파보니, 어쩌면 ref를 쓰는 게 처음부터 잘못된 설계였다는 생각이 들기 시작했다. 사실 처음에는 ref를 쓰는 것이 적당하고 여겨 도입한 것이었는데, 어떻게 쓸 건지 명확히 하고 시작했다면 이런 일은 없지 않았을까. 뭐, 이건 사담이었고, 내가 생각한 결론은 이것이다.

변화하는 값을 참조하기 위해서는 ref를 쓰는 게 옳지 않은 방향일지도...?

분명 저번에 스스로 ref의 용도에 대해 적었었는데도, 스스로 의미를 정확히 파악하지 못했던 것 같다. 그래서 다른 분이 적은 글을 다시 가져와본다.

여기서 새로 눈에 들어온 부분은 선언적으로 처리할 수 있다면 props를 이용해 선언적으로 처리하는 것을 권하고있다. 라는 부분이었다. 선언적 처리는 무엇일까?

선언적 프로그래밍 : 필요한 것을 달성하는 과정을 하나하나 기술하는 것보다 필요한 것이 어떤 것인지 기술하는 데 방점을 두고 애플리케이션의 구조를 세워 나가는 프로그래밍 구조
https://velog.io/@hyun_sang/명령형-프로그래밍과-선언적-프로그래밍-비교

선언적 프로그래밍의 반대는 명령형 프로그래밍이라고 하는데, 사실 글을 읽었음에도 약간 아리까리하다. 다음에 다시 만날 날을 기약하며 일단 선언적 프로그래밍은 넘어가려고 한다.

forwardRef()의 특성

사실 이 특성은 앞서 설명한 useRef()의 특성의 연장선상이라고 할 수 있다.

ref.current 값이 변경된다 하더라도 부모의 component에서는 알 수 없다.

앞서 설명한 useRef()의 특성은 아마 한 컴포넌트 내부에서 ref의 current 프로퍼티의 변화 값을 참조하려고 할 때도 해당될 것이다. 하지만 forwardRef()는 부모 컴포넌트와 자식 컴포넌트라는 관계가 형성되어 있을 때 사용 가능하다. 즉, 이렇게 부모 컴포넌트에서 변경 값을 참조할 수 없다는 사실은 나의 문제의 원인을 한층 더 구체화한 셈이다.

시도한 것과 시도할 만한 것 🧪

useImperativeHandle


사실 이 함수의 용도도 100% 이해한 것은 아니다. 대애충 부모 컴포넌트에서 자식 컴포넌트의 ref 값을 바꿀 수 있다는 점, ref의 프로퍼티를 커스터마이징해서 사용/참조할 수 있다는 점이 눈에 들어왔다. 뭔가 쓸모가 있지 않을까 해서 여차저차해서 적용을 해봤지만, 역시 실패였다.

forwardRef()의 userCallback

이 개념은 제대로 파고들 지 못했다. 그래서 활용이 가능할 지 안 할지도 아직 미지수다. 그래도 좀 더 보긴 봐야할 것 같다.

앞으로 참고할 관련 자료들

https://velog.io/@shyuuuuni/React-useRef-ForwardRef-활용하기
https://stackoverflow.com/questions/57278120/using-react-callback-ref-with-forwarded-ref
https://stackoverflow.com/questions/63813759/detect-when-child-ref-is-changing

마무리 📝

어쩌면 그냥 forwardRef()를 포기하고 아는 대로 state 값과 setState 값을 props로 넘기는게 더 옳은 선택일지도 모른다. 근데, 이왕 시작한 거 아는 방법대로 바로 수정하기보다 - 사실 일일히 수정하기도 귀찮.. - 기존에 있는 것을 활용해보고자 여기까지 왔다. 부디 월요일에는 잘 해결할 수 있길 바라며...
그리고 처음 공부할 때 조금 더 꼼꼼히 공부를 해야하나 싶은 생각이 들었다. 뭔가 막 세세히 들어간다는 개념보다는, 오늘처럼 어떻게서든 적어두면 기억에 조금 더 남지 않을까 싶은 생각이다. 그리고 대충이라도 제대로 중요 부분들을 짚고 넘어간다면, 처음에 설계할 때 구체적으로 구상할 수 있지 않을까?

Reference 🗂

https://2oneweek.dev/frontend/react/008.%20Hook%20-%20useRef/
https://velog.io/@shyuuuuni/React-useRef-ForwardRef-활용하기
https://leehwarang.github.io/2020/11/29/ref.html
https://sambalim.tistory.com/151
https://velog.io/@jay/useImperativeHandle-떠먹여드립니다

profile
언젠간 데이터 분석을 하고 싶은 초짜 프론트엔드 개발자입니다🙃

0개의 댓글