23.11.08 TIL

김진주·2023년 11월 8일
0

11/8

1교시

Untitled

훅은 최상위 레벨에서만 훅을 호출해야 한다

컴포넌트 내에서만 사용가능

훅은 컴포넌트가 렌더링될 때마다 매번 같은 순서로 렌더링되어야 한다

useState

초기값 설정시 무거운 계산이 동반되는 경우 콜백함수로 작성!

useEffect

  1. 렌더링될 때마다 실행
  2. 첫번째 렌더링 시에만 실행
  3. 첫 렌더링 + 특정값이 변할 때
  4. 클린업

2교시

useState 콜백 & useMemo 용도의 차이점

  • 설명 https://www.zigae.com/useState-one-initialization/
    해당 포스트가 잘 설명해주고있는 것 같습니다.
    제가 이해한 바로는
    1. state는 참조 동일성을 보장(setter에 의해서만 변경)
    2. useMemo는 불필요한 재연산을 방지
      에 초점을 맞춰 사용하는 게 바람직하다' 인 것 같습니다.
      https://careerly.co.kr/comments/87690
      Hooks의 실행순서는 렌더링 과정에서 동일하지만 useMemo에서 'not as a semantic guarantee' 라고 적혀있는 반면
      https://legacy.reactjs.org/docs/hooks-reference.html#lazy-initial-state
      State의 초기값에서는 초기 렌더링시점에 대한 언급이 존재합니다.
      The initialState argument is the state used during the initial render
      강사님이 보여주셨던 예제에서는(무거운 연산에 한해서) 동일하게 동작하는 것 같은데 리액트에서는 순서에 대해 언급한 의도가 책임 못지니 용도에 맞게 (참조 동일성/재연산 방지) 사용해라가 핵심인 것 같습니다!

🧞‍♂️ 순서가 상관 없으면 useMemo 순서가 중요하면 useState callback

3교시

제네릭 타입을 사용하는 이유

사용자한테 권한을 주는 것

useRef

ref는 컴포넌트 전 생애주기를 통해 유지가 된다.

= 리렌더링되어도 값을 유지

  1. 특정 상태값이 변할 때, 리렌더링 시키면 안되는 상태값인 경우
  2. 컴포넌트 내 특정 돔 요소에 접근해야 하는 경우
  3. 부모 컴포넌트가 자식 컴포넌트의 돔에 접근해야 하는 경우 (forwardRef)
  • forwardRef https://www.daleseo.com/react-forward-ref/ 자식컴포넌트의 돔이 외부로 노출되는 것이기 때문에 가독성에 부정적인 영향을 줍니다. 이상으로 React의 forwardRef() 함수를 사용하여 어떻게 React 컴포넌트에 ref prop을 넘길 수 있는지에 대해서 알아보았습니다. 일반적으로 forwardRef() 함수는 HTML 엘리먼트 대신에 사용되는 최말단 컴포넌트(ex. , )를 대상으로 주로 사용되며, 그 보다 상위 컴포넌트에서는 forwardRef() 함수를 사용하는 것이 권장되지 않습니다. 왜냐하면 어떤 컴포넌트의 내부에 있는 HTML 엘리먼트의 레퍼런스를 외부에 있는 다른 컴포넌트에서 접근하도록 하는 것은 컴포넌트 간의 결합도(coupling)을 증가시켜 애플리케이션의 유지보수를 어렵게 만들기 때문입니다.

만보기 앱을 만들 때 useRef를 사용해야 하는 곳과 그 이유

시간과 걸음수가 있을 때 걸음 수에 useRef를 사용하여 값을 유지해야 한다고 생각한다.

걸음수는 하루의 전체 걸음수를 표시해주어야 하기 때문에 리렌더링이 발생한다고 값이 사라지면 안 되고 계속 누적되어 나중에 결과를 표시해주어야 하기 때문이다

4교시

useContext

context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다

Redux와 Context API의 차이

  • Redux가 Context API에 비해 가지는 강점
    • 리덕스는 로컬 스토리지에 상태를 영속적으로 저장하고 시작할 때 다시 불러오는데 뛰어남
    • 상태를 서버에서 미리 채워서 HTML에 담아 클라이언트로 보내고 앱을 시작할 떄 다시 불러오는데 뛰어남
    • 사용자의 액셕을 직렬화해서 상태와 함꼐 자동으로 버그리포트에 첨부할 수 있고 개발자들은 이를 통해 에러를 재현할 수 있음
    • 액션 객체를 네트워크를 통해 보내면 코드를 크게 바꾸지 않고도 협업 환경을 구현할 수 있음
    • 실행취소 내역의 관리나 낙관적인 변경 (optimistic mutations)을 코드를 크게 바꾸지 않고도 구현 가능
    • 개발할 때 상태 내역 사이를 오가고 액션 내역에서 현재 상태를 다시 계산하는 일을 TDD스타일로 할 수 있음
    • 개발자 도구에게 완전한 조사와 제어를 가능하게 해서 개발자들이 자신의 앱을 위한 도구를 직접 만들 수 있게 해줌
    • 비즈니스 로직 대부분을 재사용하면서 UI를 변경할 수 있게 해줌
  • 차이점

    Redux:

    1. 예측 가능한 상태 관리: Redux는 애플리케이션 전체의 전역 상태를 중앙 집중식으로 저장하고 관리합니다.

    2. 단일 스토어: Redux는 단일 스토어를 사용하며, 앱의 상태를 여러 개의 리듀서로 분할하여 관리합니다.

    3. 불변성 유지: Redux는 불변성을 유지하며, 상태를 변경할 때 항상 새로운 상태 객체를 반환합니다.

    4. Middleware: 미들웨어를 사용하여 액션과 리듀서 사이에 추가 기능을 삽입할 수 있습니다. 예를 들어, 비동기 작업을 처리할 수 있습니다.

    5. Redux DevTools: Redux는 강력한 개발 도구를 제공하여 애플리케이션 상태의 시간 여행 및 디버깅을 용이하게 합니다.

      Context API:

    6. 로컬 상태 관리: React의 Context API는 주로 특정 컴포넌트 트리 내에서 데이터를 공유하기 위한 용도로 사용됩니다.

    7. 하위 컴포넌트에 전달: Context를 사용하여 값을 전달하면 해당 값에 접근할 수 있는 컴포넌트는 해당 Context를 구독하고 있는 컴포넌트 뿐입니다.

    8. 간편한 사용: 상대적으로 Redux보다 더 간단하게 사용됩니다. 주로 특정 컴포넌트 간의 데이터 전달이 목적입니다.

    9. 적은 양의 데이터 전달: 일반적으로 Redux보다는 소규모 애플리케이션이나 단순한 데이터 전달에 사용됩니다.

  • 오직 전역 상태 관리를 위한다면 Context API를 사용하라.
  • 상태 관리 외에 여러 기능이 필요하다면 Redux 를 사용하라.
  • high-frequency한 어플리케이션의 경우 Context API를 사용하면 성능상 이슈가 있을 수 있다.
  • Redux는 크고 복잡한 애플리케이션에서 상태를 효과적으로 관리하는 데 유용,
  • 반면에 Context API는 상대적으로 작은 규모의 애플리케이션에서 로컬 상태 관리나 특정 컴포넌트 간의 데이터 전달에 활용

5교시

useMemo / useCallback을 사용하는 것이 항상 성능을 향상시키는 것이 아니다 그 이유는?(힌트: 참조 동일성)

  • 설명
    const Foo = () => {
      const [count, setCount] = useState(0);
    
      // case 1
      const handleIncrement = useCallback(() => {
        setCount(count + 1);
      }, []);
    
      // case 2
      const handleIncrement = () => {
        setCount(count + 1);
      };
    
      return <Box *onClick*={handleIncrement} />;
    };
    case1과 case2 중에 비용이 적게 드는 코드는 어느쪽일까? 많은 아티클에서 inline 함수는 useCallback 으로 안에 넣는 것이 성능에 더 좋다 말하고 있기 때문에 case1을 선택할 수 있겠지만 실상은 그렇지 않다. 모든 추상화 및 최적화 코드에는 비용이 들기 마련이다. 이때 발생하는 비용을 상쇄 시킬만한 비용절약이 있지 않으면 오히려 비용 증가가 일어난다. 최적화 관점에서 useCallback을 사용하기 위해선 전후 성능을 비교 후에 사용하는 것이 옳다.

    참조 동일성

    객체, 배열 같은 참조타입일 경우 렌더링될 때마다 객체가 새로 만들어지고 렌더링될 때마다 계속 호출되게 된다. 이 때 useCallback이나 useMemo를 사용하여 캐싱하고 싶어도 아무의미없이 컴포넌트는 리렌더링될 때마다 실행되게 된다. 따라서 무조건 useCallback을 사용하거나 useMemo를 사용한다고 해서 무조건 비용이 절감되는 것이 아니고 코드도 더 복잡해질 수 있다
    • useCallback과 useMemo를 성능을 향상시킨다는 초점에 맞춰서 무분별하게 사용한다면??
      • 코드가 더 복잡하게 보일수도 있으며 팀원들이 이해하기에 복잡성 또한 증가할 수 있습니다.
      • dependencies 배열에 들어가는 참조 value들이 누락되거나 잘못 넣게되면서 휴먼 에러가 자주 발생합니다.
      • dependencies 배열 내부의 값들이 메모제이션되면서 가비지 컬랙터가 안되게 만들 수 있습니다.
      • 성능 개선을 위해 추가된 비용때문에 오히려 효율성이 떨어져 성능이 더 하락할 수 있습니다.
    • 즉 적절한 상황에서 useCallback과 useMemo를 사용하여 성능 개선을 통해 얻어지는 이점이 추가된 비용을 상쇄할 수 있다면 의미있게 사용할 수 있지 않을까? 생각합니다!

6교시

useReducer

useState와 비슷하지만 복잡한 상태(중첩된 객체 nested object)를 관리하는데 사용

또는 이전상태에 의존하는 상태를 관리하는데 사용

Untitled

useReducer를 사용할 때, action, dispatch, reducer에 대해 설명해주세요.

  • 설명 useReducer는 React에서 제공하는 훅 중 하나로, 상태 관리를 위해 사용됩니다. 기존의 useState와 달리, 복잡한 상태 논리를 처리하고 상태를 업데이트하기 위한 더 구조화된 방법을 제공
    • Reducer: Reducer는 현재 상태와 업데이트하고자 하는 액션을 받아 새로운 상태를 반환하는 함수입니다. Reducer는 (이전 상태, 액션) => 새로운 상태의 형태를 갖습니다. 여기서 "액션"은 상태를 어떻게 변경할지에 대한 정보를 가지고 있습니다.
    • Dispatch: dispatch 함수는 Reducer에게 상태를 변경하라는 명령을 내리는 함수입니다. 액션 객체를 인자로 받아 Reducer에게 전달하고, Reducer가 이에 따라 상태를 업데이트합니다.
    • Action: 액션은 상태를 변경하는 유형을 나타내는 객체입니다. 일반적으로 "type"이라는 필드를 포함하고 있으며, Reducer에서 어떤 종류의 업데이트를 수행할지 식별하는 데 사용됩니다. 추가적인 데이터를 전달해야 할 경우, "payload" 또는 기타 필드를 포함할 수 있습니다.

useReducer에서 액션을 처리할 때 주의해야 할 점은 무엇인가요?

(Hint 순수함수)

  • 이유 useReducer에서 액션을 처리할 때 주의해야 할 점 중 하나는 순수 함수를 사용해야 한다는 것입니다. 순수 함수란 다음과 같은 특징을 갖는 함수를 의미합니다:
    1. 부수 효과(side effects)가 없어야 합니다: 순수 함수는 함수 내부에서 외부의 상태를 변경하거나 외부에 영향을 미치는 작업을 수행해서는 안 됩니다. 외부 상태에 변경을 가하지 않아야 합니다.

    2. 동일한 입력에 대해서는 항상 동일한 출력을 반환해야 합니다: 함수는 동일한 인자(입력)에 대해 항상 같은 결과(출력)를 반환해야 합니다. 외부 상태의 변화나 무작위 요소 등이 없어야 합니다.

      액션을 처리하는 함수인 리듀서는 순수 함수여야 합니다. 외부의 상태를 변경하면 안 되며, 같은 액션에 대해 항상 같은 결과를 반환해야 합니다. 왜냐하면 useReducer는 순수 함수인 리듀서를 통해 이전 상태와 액션을 바탕으로 새로운 상태를 반환하는데, 이 규칙을 어겨버리면 예상치 못한 문제가 발생할 수 있습니다.

      순수 함수를 유지하여 예측 가능하고 안정적인 상태 업데이트를 보장하면서, 코드의 테스트 용이성도 높아집니다. 따라서 리듀서에서는 순수 함수의 원칙을 준수하여 액션을 처리해야 합니다.

초기 상태가 복잡한 계산이 필요할 때, useReducer를 사용할 때 초기 상태를 지연 초기화하는 방법은 무엇인가요?

  • 방법 useReducer를 사용할 때 초기 상태가 복잡한 계산이 필요하거나 지연 초기화해야 할 때, 보통 초기 상태를 계산하는 함수를 사용합니다. 여기서 useReducer의 초기값으로 함수를 전달할 수 있습니다. 이 함수는 실제 초기 상태를 계산하고 반환하는 역할을 합니다. 이를 통해 초기 상태가 복잡한 계산이 필요한 경우 해당 함수를 호출하여 초기 상태를 반환하도록 할 수 있습니다

7교시

customHook

profile
진주링딩동🎵

0개의 댓글