[React Native] Class Component -> Functional Component (클래스 컴포넌트 함수형 컴포넌트로 전환하기 )

bi_sz·2023년 11월 2일
0

ReactNative

목록 보기
23/37
post-thumbnail

지난 게시글 https://velog.io/@bi-sz/ReactNative-Component 에서 Class Componet 들을 만들어두었는데, 이 컴포넌트들을 functional Component 로 변경해보고 사용할 hook 들은 추가해보도록 하겠습니다!

기존에 만들어둔 example_component 프로젝트에서 수정하지 않고 copy 하여 functional_component 로 프로젝트명을 변경하여 진행하였습니다.

class component 를 만들었던것과 비슷하게 가장 작은 단위부터 변경하겠습니다.


클래스 컴포넌트 함수형 컴포넌트로 전환하기

⭐ ATOM Component ⭐

💫 Typography

class componentfunctional component 로 변환해주었습니다.

차이점으로는 render() 함수가 없어졌고, Typography 를 함수로 부르고, element를 바로 return 해줍니다.

this.props 에서 props 로 변경되었습니다.

App.js 에서는 기존 코드는 다 날리고 Typography만 사용하여 TEXT 를 출력해주었습니다.

TEXT 가 잘 표시되네요!


💫 Image

LocalImage

RemoteImage

LocalImageRemoteImage 도 변경해주었습니다.

App.js에서 추가하여 확인해보겠습니다.

잘 보여지네요!


💫 Spacer

Spacerhorizontal 에 따라 분기해주었던 코드입니다.

삼항연산자 로 표현도 가능하고 원래의 방식대로 if 문으로도 가능합니다.

삼항연산자 보다는 early return 방식이 좀 더 가독성이 좋고 직관적이기 때문에 early return 방식으로 해주겠습니다.

App.js 에서 Spacer를 사용해주었습니다.
horizontal도 확인해보기 위헤 View로 감싸주고 이미지를 하나 더 추가해주고, 그 사이에 Spacer를 넣어주었습니다.

여백이 잘 들어가네요!


💫 Divider

마찬가지로 변경 후 App.js 에서 사용해주었습니다.

구분선이 잘 보여지네요!

💫 Badge

💫 Button

💫 Icon

💫 TabIcon

간단한 반복작업이라 나머지는 확인하지 않았습니다.. ㅎㅎ


⭐ MOLCULE Component ⭐

💫 Header

상단 노치(Notch) 영역을 제외하기 위해서 SafeAreaInestsContext 를 이용하여 하였는데, 이 부분은 hook 으로 대체해줍니다.

기존에는 Dimensions.get('window')width를 가져왔는데 useWindowDimensions 라는 hook을 통해 width 를 가져와주었습니다.

useSafeAreaInsets 라는 hook 을 통해서 insetsTop이 얼마나 되는지도 간단하게 가져와주었습니다.

class component 에서는 inset이라는 별도의 함수를 받아서 처리했었는데 hook을 사용하면서 훨씬 간결해졌습니다.

App.js에서 다른 코드들은 날리고 Header를 적용해주었습니다.

Header 화면이 잘 표시되네요!


⭐ Memoization ⭐

Memoization 는 최적화를 위해 사용하게 됩니다.
functional component 에서 가장 중요하게 이루어지는 부분입니다.

functional component 에서는 함수 호출 자체가 render 입니다.
render 가 일어나려면 반드시 함수가 호출됩니다.

export const ComponentA = (props) => {
  const variableA = 10;
  const testFunction = () => {}
}

함수 호출을 하며 생긴 함수 내부의 변수, 함수 등은 모두 호출될 때마다 새로 할당됩니다.

연산의 결과값 함수등을 매번 새롭게 생성하고 저장하게됩니다.

만들어져있고 재활용하는 값이라면 굳이 새로 만들 필요가 없습니다

Memoization 를 이용해서 기존에 수행했던 연산의 결과값들을 어딘가에 저장하고, 동일한 입력값인 경우 재활용할 수 있습니다.

💫 Memoization 을 도와주는 hook

🔸useMemo

useMemo 는 값에대한 Memoization 값을 제공해줍니다.

export const ComponentA = (props) => {
  const variableA = useMemo(() => {}, [])
  }

useMemo 라는 hook 을 선언하고, 첫 번째 인자로 어떤 값을 return 하는 함수를 만들고 두 번째 인자로는 배열을 넣어줍니다.

  • 첫 번째 인자로 전달해줄 함수는 기억할 값을 return 해주는 함수입니다.
    -> 값은 string number object 등이 올 수 있고, 단순하게 어떤 값을 지칭 함수로 되어있다 보니 내부에서 조건을 걸어 return 을 해줄 수 도 있습니다.

  • 두 번째 배열에서는 값을 언제 return 해줄지를 알 수 있습니다.
    -> useEffect의 두 번째 인자인 배열의 역할과 비슷합니다.

의존성 배열 (Dependency Array)
의존성 배열(Dependency Array)은 useEffect, useCallback, useMemo 등의 Hook 에서 사용되는 배열로, Hook 이 불필요하게 반복해서 실행되는 것을 방지하여 성능을 최적화하기 위해서 사용합니다

  • 배열안에 어떤 값을 넣고 값이 변경되면, 함수 안의 값이 변경되며 결과를 다시 갱신해줍니다.
  • useMemo 에선 값을 갱신하는걸로 주로 사용하고 Effect는 첫 번째의 함수를 호출하는 용도로 사용됩니다.
  • 의존성 배열을 사용하는 이유
    -> 항상 호출되는 함수형 컴포넌트는 값이 변경됨을 알 수 잇는 방법중에 가장 빠른 방법이 이전에 갖고있던 값 과 현재 호출된 값들을 비교하는 것입니다. 배열의 비교를 통해 변경여부를 바로 캐치할 수 있습니다.

useMemo 예시

propsab 두 가지 값을 받고, useMemo를 통해 더해주는 작업을 한다고 가정해보았습니다.

export const ComponentA = (props) => {
  //props.a = 1, props.b = 1
  const variableA = useMemo(() => {
    return props.a + props.b
  }, [props.a, props.b])
}

props 를 통해서 component 를 만들고

variableAuseMemo를 통해서 받고있습니다.
props.a = 1, props.b = 1 일 때, variableA2라는 값을 갖게됩니다.

여기서 props 이 변경된다면 다시 render가 일어나면서 useMemo가 한 번더 호출됩니다.

Dependency Arrayprops이 선언되어있지 않은 상태라면,
a ,b가 변경되지 않은것으로 인식하여 variableA 의 결과값은 항상 2return 됩니다.

Dependency Arrayprops 정상적으로 들어가있다면 a, 혹은 b 가 변경된 것을 인지히고, useMEmo 를 다시 호출하면서 variableA 은 변경된 값으로 값을 구하여 return 됩니다.


🔸useCallback

export const ComponentA = (props) =< {
  const variableA = useCallback(() => {}, [])
}

javaScript 에서는 함수를 변수처럼 저장할 수 있습니다.

useMemo와 거의 유사하며 useCallbackDependency Array 가 변경되면, 함수를 다시 재생성 해줍니다.

첫 번째 인자에는 기억할 함수를 리턴해주는 함수를 넣어주고, 두 번째 인자는 Dependency Array 입니다.

useMemouseCallback 를 사용한다고 해서 사용자의 눈에 띌만한 변경은 거의 없습니다.

사용효과가 직관적으로 눈에 보이지는 않지만, 앱이 최초의 설계보다 커지게되고, 함수형 컴포넌트가 비대해지면, 메모리가 점점 늘게되면서 앱이 강제 종료되는 경우가 있습니다.

항상 값을 생성하고 앱의 사용시간이 길어질수록 발생하는 대표적인 문제입니다. 이런 경우에는 Memoization 를 사용하여 문제를 해결합니다.

💫 Memoization 사용해보기

🔸useMemo

src 폴더의 components 폴더 안에 HookTestComponent.js 파일을 만들어주었습니다.

propsab 두 가지 값을 받고, useMemo를 통해 더해주는 text 를 선언하고, 결과값을 return 해주었습니다.

App.js에서 View로 감싸주고, HookTestComponet를 사용해주었습니다. ab10 을 넣어주었습니다.

결과값 20 이 표시됩니다.

현재는 props 가 있기 때문에 정상적으로 동작합니다.

버튼을 넣어 a 값과 b 값을 변경할 수 있도록 수정해주겠습니다.

a, setA 함수를 만들고 state를 통해서 0을 기본값으로 넣어주었습니다. b도 마찬가지로 만들어주었습니다.

결과값은 0 이 표시됩니다.

클릭하면 a 값에 1을 더해주는 버튼을 만들어주었습니다.

버튼을 클릭할 때마다 a 값이 +1 되면서 결과값이 변하는 것을 확인할 수 있습니다.

useMemoDependency Arrayprops.aprops.b 가 있기 때문에 propsa 의 변화를 감지하여 useMemo가 실행되고 return 값이 변경되는 것입니다.

Dependency Arrayprops.a 를 지우고 props.b 만 남겨주었습니다.

아무 동작을 안 하고 있는 것 처럼 보이지만 열심히 버튼을 누르고 있는 모습입니다. 버튼을 아무리 눌러도 결과값이 변하지 않습니다.

Dependency Array 에는 props.b 만 남아있습니다.
a 값만 변경될 뿐, b 값은 변경되지 않았기 때문에, 변경을 감지하지 않아 저장된 값을 그대로 return 해주는 모습입니다.

Dependency Arrayprops.a 를 다시 추가해주자, 결과값이 바로 변경되는 것을 확인할 수 있습니다.

🔸useCallback

useCallback hook 을 이용한 doSum을 선언해주었습니다.

버튼을 클릭하여 a 값이 증가함에 따라 useMemo를 사용한 text 결과값과, useCallback 을 사용한 값이 변하는 것을 확인할 수 있습니다.

useMemo 와 마찬가지로 Dependency Arrayprops.a 값이 변경됨을 감지하여 return 값이 변경됩니다.

Dependency Arrayprops.a 빼주었습니다.

버튼을 클릭하여 a 값을 증가시켜주었습니다.

결과값인 useMemoDependency Array 에는 props.a, props.b 가 전부 들어있어 변경을 감지하여 새로운 return 값을 보여줍니다.

useCallbackDependency Array 에는 props.a 가 없기 때문에 변경을 감지하지 못해 return 이 변하지 않습니다.


정리

기존에 class Componet 로 작성해둔 부분을 functional component 로 변환해주었습니다.

앞으로 이 컴포넌트들을 재활용하고 업데이트하여 사용해서 반복작업을 줄일 수 있겠네요!

추가적으로 MemoizationuseMemo, useCallback 을 이용하여 최적화하는 방법까지 학습하였습니다.


참고

https://velog.io/@bi-sz/ReactNative-Component

https://velog.io/@bi-sz/ReactNative-hook

0개의 댓글