React Docs 읽기 체크 / 내용 메모

SeoYng·2022년 9월 18일
1
post-thumbnail

[ 🌱 함께자라기 🌱 ]
React 공식문서를 정독하고 필요한 부분을 메모
🪂 공식문서

⭐️ 주요개념

  1. ☑ Hello World
  2. ☑ JSX 소개
  3. ☑ 엘리먼트 렌더링
  4. ☑ Component와 Props
  5. ☑ State와 생명주기
  6. ☑ 이벤트 처리하기
  7. ☑ 조건부 렌더링
  8. ☑ 리스트와 Key
  9. ☑ 폼
  10. ☑ State 끌어올리기
  11. ☑ 합성 vs 상속
  12. ☑ React로 생각하기

✏️ note

  • JSX는 HTML보다는 JavaScript에 가깝기 때문에,
    camelCase 프로퍼티 명명 규칙을 사용

  • 모든 항목은 렌더링 되기 전에 문자열로 변환
    이런 특성으로 인해 XSS (cross-site-scripting) 공격을 방지

  • Babel은 JSX를 React.createElement() 호출로 컴파일

  • React 엘리먼트 렌더링 과정

    ReactDOM.createRoot(...) & root.render(...)
  • UI를 업데이트하는 유일한 방법은 새로운 엘리먼트를 생성하고 이를 root.render()로 전달하는 것 => React 엘리먼트는 불변객체이기 때문

  • React 컴포넌트는 props를 다룰 때 반드시 순수 함수처럼 동작해야함

  • State 업데이트는 비동기적일 수도 있음
    => 성능을 위해 여러 setState() 호출을 단일 업데이트로 한꺼번에 처리
    ❗️다음 state를 계산할 때 해당 값에 의존하면 안됨 => 💡**인자를 함수로!!**

    // 비동기로 처리되어 원하는 결과값이 나오지 않음 => +1
      const plus1 = () => {
        setCount(count + 1);
        setCount(count + 1);
      };
    // 인자를 함수로 전달 => +2
      const plus2 = () => {
        setCount((count) => count + 1); // 현재 state를 참조하지 않고 state를 변경해야 하는 방법
        setCount((count) => count + 1); // setCount에 대한 내부 호출이 count에 최신 값을 사용
      };

    참고 - 코드펜에 작성해봄
    => 이전 state를 사용해서 새로운 state를 계산하는 경우 함수를 setState 로 전달 가능

  • 단방향식 데이터 흐름
    => 모든 state는 항상 특정한 컴포넌트가 소유,
    그 state로부터 파생된 UI 또는 데이터는 자신의 “아래”에 있는 컴포넌트에만 영

  • 조건이 false라면 React는 무시하고 건너뜁니다.
    falsy 표현식을 반환하면 여전히 && 뒤에 있는 표현식은 건너뛰지만
    ❗️falsy 표현식이 반환된다는 것에 주의

    return (
        <div>
          {unreadMessages.length > 0 &&
            <h2>You have unreadMessages</h2> // 무시됨
          }
        </div>
      );
    
    // <div>0</div>
    render() {
      const count = 0;
      return (
        <div>
          {count && <h1>Messages: {count}</h1>}
        </div>
      );
    }
  • 가끔 다른 컴포넌트에 의해 렌더링될 때 컴포넌트 자체를 숨기고 싶을 때
    => 렌더링 결과를 출력하는 대신 null을 반환하면 해결

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }
  ...
}
  • 안정적인 ID가 없다면 최후의 수단으로 항목의 인덱스를 key로 사용
  • 항목의 순서가 바뀔 수 있는 경우 key에 인덱스를 사용하면
    성능이 저하되거나 컴포넌트의 state와 관련된 문제가 발생
    가능

Index as a key is an anti-pattern

1️⃣ the list and items are static–they are not computed and do not change;
2️⃣ the items in the list have no ids;
3️⃣ the list is never reordered or filtered.

👉 세가지 다 만족하는 경우 안전하게 index를 key로 사용

  • Key는 배열 안에서 형제 사이에서 고유해야 하고 전체 범위에서 고유할 필요는 없음
    => 두 개의 다른 배열을 만들 때 동일한 key를 사용 가능

  • 제어 컴포넌트 (Controlled Component)
    React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트 -> input의 값은 항상 React state에 의해 결정
    => 신뢰 가능한 단일 출처 (single source of truth)
    +❓🤔 vue의 v-model와 차이점은 뭘까

  • React에서는 selected 어트리뷰트를 사용하는 대신 최상단 select태그에 value 어트리뷰트를 사용

    <select value={this.state.value} onChange={this.handleChange}>
       <option value="grapefruit">Grapefruit</option>
       <option value="lime">Lime</option>
    </select>
  • select 태그에 multiple 옵션을 허용한다면 value 어트리뷰트에 배열을 전달

<select multiple={true} value={['B', 'C']}>
  • file input 태그는 값이 읽기 전용이기 때문에 비제어 컴포넌트

  • state를 끌어올리는 작업(Lifting state up)은 양방향 바인딩 접근 방식보다 더 많은 *보일러 플레이트 코드를 유발하지만, 버그를 찾고 격리하기 더 쉽게 만듬

  • React는 강력한 합성 모델을 가지고 있으며,
    상속 대신 합성을 사용하여 재사용하는 것을 권장

  • 합성의 방법은 담기(Containment)와 특수화(Specialization)

  • Containment는 props.children을 사용하여 상위 컴포넌트에서 정의한 자식 요소들을 출력

    function WelcomeDialog() {
      return (
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            Welcome
          </h1>
        </FancyBorder>
      );
    }
    
    function FancyBorder(props) {
      return (
        <div>
          {props.children} // 여기에 h1태그 출력됨
        </div>
      );
    }

    +❓🤔 vue의 slot이랑 차이점은 뭘까

  • Specialization은 구체적인 컴포넌트가 일반적인 컴포넌트를 렌더링하고 props를 통해 내용을 구성

  • 단일책임원칙 : 하나의 컴포넌트는 한 가지 일을 하는게 이상적이라는 원칙

  • 리액트로 사고하기 5단계

    1️⃣ UI를 컴포넌트 계층 구조로 나누기
    2️⃣ React로 정적인 버전 만들기
    3️⃣ UI state에 대한 최소한의 표현 찾아내기
    => 중복배제원칙(DRY) : 가장 최소한의 state
    4️⃣ State가 어디에 있어야 할 지 찾기
    5️⃣ 역방향 데이터 흐름 추가하기

  • state가 되기 위한 조건
    1) 부모로부터 props를 통해 전달되지 않아야 함
    2) 시간이 지나면 변해야 함
    3) 컴포넌트 안의 다른 state나 props를 가지고 계산 가능하지 않아야 함

  • state 소유하는 컴포넌트 찾기
    1) 공통 혹은 더 상위에 있는 컴포넌트가 state를 가져야 함
    2) 적절한 컴포넌트를 찾지 못하였다면, 공통 소유 컴포넌트의 상위 계층에 추가

🪡 HOOK

  1. ☑ Hook 소개
  2. ☑ Hook 개요
  3. ☑ State Hook 사용하기
  4. ☑ Effect Hook 사용하기
  5. ☑ Hook 규칙
  6. ☑ 자신만의 Hook 만들기
  7. ☑ Hook API 참고서
  8. ☑ Hook 자주 묻는 질문

🪡 Hook
함수 컴포넌트에서 React state와 생명주기 기능을 연동(hook into)할 수 있게 해주는 함수
=> class 없이 React를 사용할 수 있게 해줌

  • Hook은 React 버전 16.8부터 React 요소로 새로 추가,
    기존 Class 바탕의 코드를 작성할 필요 없이 상태 값과 여러 React의 기능을 사용

  • Hook의 등장배경 및 장점
    1) Hook은 계층의 변화 없이 상태 관련 로직을 재사용할 수 있도록 도와줌
    2) 생명주기 메서드를 기반으로 쪼개는 것 보다는, Hook을 통해 서로 비슷한 것을 하는 작은 함수의 묶음으로 컴포넌트를 나누는 방법을 사용가능 (useEffect)
    => Hook을 사용하면 구독을 추가하고 제거하는 로직과 같이 서로 관련 있는 코드들을 한군데에 모아서 작성가능, 반면 class 컴포넌트에서는 생명주기 메서드 각각에 쪼개서 넣어야만 함
    결론적으로 코드가 무엇을 하는지에 따라 나눌 수가 있음
    3) Class 컴포넌트가 최적화를 더 느린 경로로 되돌리는 의도하지 않은 패턴을 장려할 수 있다는 것이 발견됨
    4) Class는 코드의 최소화를 힘들게 만들고, 핫 리로딩을 깨지기 쉽고 신뢰할 수 없게 함

  • useState는 class의 this.setState와 거의 유사하지만, 이전 state와 새로운 state를 합치지 않음

  • useState초기값은 첫 번째 렌더링에만 딱 한번 사용

  • 다른 컴포넌트에 영향을 줄 수도 있고, 렌더링 과정에서는 구현할 수 없는 작업 등을 side effects라고 함, useEffect는 함수 컴포넌트 내에서 이런 side effects를 수행
    => ex) 데이터 가져오기, 구독(subscription) 설정하기, 수동으로 React 컴포넌트의 DOM을 수정하는 것 등

  • useEffect는 React class의 componentDidMountcomponentDidUpdate, componentWillUnmount와 같은 목적으로 제공되지만, 하나의 API로 통합된 것

useEffect

  • Effects는 컴포넌트 안에 선언되어있기 때문에 props와 state에 접근가능

  • ❗️ Hook 사용 규칙
    1) 최상위에서만 Hook을 호출.
    반복문, 조건문, 중첩된 함수 내에서 Hook을 실행 x
    => React가 특정 state가 어떤 useState 호출에 해당하는지 알기위해 Hook이 호출되는 순서에 의존하기 떄문

2) React 함수 컴포넌트 내에서만 Hook을 호출.
일반 JavaScript 함수에서는 Hook을 호출 x

  • 상태 관련 로직을 컴포넌트 간에 재사용하고 싶은 경우
    전통적으로 고차 컴포넌트render props 사용,
    Custom Hook은 이들 둘과는 달리 컴포넌트 트리에 새 컴포넌트를 추가하지 않음

  • Custom Hook은 기능이라기보다는 컨벤션
    1) 이름이 use로 시작하고
    2) 안에서 다른 Hook을 호출

  • 일반적으로 일반 변수는 함수가 끝날 때 사라지지만, state변수는 React에 의해 사라지지 않음

  • useState는 클래스 컴포넌트의 this.setState와 달리 state를 갱신하는 것은 병합하는 것이 아니라 대체하는 것

  • useEffect Hook을 이용하여 우리는 React에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지를 말함
    => React는 함수를 기억했다가 DOM 업데이트를 수행한 이후에 call

  • useEffect를 컴포넌트 안에서 불러내는 이유: 클로저를 이용하여 state, prop에 접근 가능

  • 리렌더링하는 때마다 모두 이전과 다른 effect로 교체하여 전달
    => 각각의 effect는 특정한 렌더링에 속하게 됨

  • componentDidMount 혹은 componentDidUpdate와는 달리 useEffect는 브라우저가 화면을 업데이트하는 것을 차단 x
    즉, 레이아웃 배치와 그리기를 완료한 후 발생
    => 이를 통해 애플리케이션의 반응성을 향상

  • useEffect비동기적 실행
    💡 동기적 실행이 필요한 경우에는 useEffect와 동일한 API를 사용하는 useLayoutEffect라는 별도의 Hook이 존재

  • useEffect 는 컴포넌트들이 render 와 paint 된 후 실행
    useLayoutEffect는 컴포넌트들이 render 된 후 실행되며 그 이후에 paint
    참고) useEffect vs useLayoutEffect

  • effect는 한번이 아니라 렌더링이 실행되는 때마다 실행
    => React가 다음 차례의 effect를 실행하기 전에 이전의 렌더링에서 파생된 effect 또한 정리하는 이유

  • setState는 안정적이고 리렌더링 시에도 변경되지 않을 것이라는 것을 보장
    => useEffect나 useCallback 의존성 목록에 이 함수를 포함하지 않아도 무방

  • initialState 인자는 초기 렌더링 시에 사용하는 state로 이후의 렌더링 시에는 이 값은 무시됨
    초기 state가 고비용 계산의 결과라면, 초기 렌더링 시에만 실행될 함수를 대신 제공

    const [state, setState] = useState(() => {
      const initialState = someExpensiveComputation(props);
      return initialState;
    });
  • 다수의 하윗값을 포함하는 복잡한 정적 로직을 만드는 경우나 다음 state가 이전 state에 의존적인 경우에 보통 useState보다 useReducer를 선호

  • useReducer는 자세한 업데이트를 트리거 하는 컴포넌트의 성능을 최적화할 수 있게 하는데, 이것은 콜백 대신 dispatch를 전달 할 수 있기 때문

  • useReducer 초기화지연방법: init 함수를 세 번째 인자로 전달

    useReducer(reducer, initialCount, init);
  • useCallback메모이제이션된 콜백을 반환하며 콜백의 의존성이 변경되었을 때에만 변경
    불필요한 렌더링을 방지하기 위해 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용

  • useMemo메모이제이션된 값을 반환하며 의존성이 변경되었을 때에만 메모이제이션된 값만 다시 계산
    => 모든 렌더링 시의 고비용 계산을 방지

  • useMemo로 전달된 함수는 렌더링 중에 실행
    => ❗️ effects같이 렌더링 중에는 하지 않는 것을 이 함수 내에서 하면 안됨

  • useRef.current 프로퍼티변경 가능한 ref 객체를 반환하며
    매번 렌더링을 할 때 동일한 ref 객체를 제공

  • useRef는 매번 렌더링을 할 때 동일한 ref 객체를 제공

  • ❗️ useRef는 내용이 변경됨을 알려주지는 않아 .current 프로퍼티를 변형하는 것이 리렌더링을 발생시키지는 않음
    => React가 DOM 노드에 ref를 attach하거나 detach할 때 어떤 코드를 실행하고 싶다면 대신 콜백 ref를 사용

  • 부모 컴포넌트에서 자식컴포넌트의 ref를 사용하고 싶을 때 useImperativeHandle사용

    /* 
    <FancyInput ref={inputRef} />를 렌더링한 부모 컴포넌트는 
    inputRef.current.focus()를 호출 가능
    */
    function FancyInput(props, ref) {
      const inputRef = useRef();
      useImperativeHandle(ref, () => ({
        focus: () => {
          inputRef.current.focus();
        }
      }));
      return <input ref={inputRef} ... />;
    }
    FancyInput = forwardRef(FancyInput); // forwardRef와 더불어 사용
  • useDeferredValue 는 debounce, throttling과 같은 역할을 함
    활용 사례

  • useTransition은 일부 상태 업데이트를 급하지 않은 업데이트로 간주하여 급한 상태 업데이트가 급하지 않은 상태 업데이트를 중단할 수 있음

  • useId는 client-server사이드에서 hydration(HTML 코드와 JS 코드를 서로 매칭시켜 동적인 웹사이트를 브라우저에 랜더링하는 기술)미스매치를 피하기 위해서 unique ID를 만들어주는 훅
    ❗️ list의 key를 만들어주기 위한 훅이 아님

  • useInsertionEffectuseEffect와 비슷하지만 모든 돔 변화 이전에 실행되며 레이아웃을 읽기전 스타일 주입을 위해 사용

  • shouldComponentUpdate구현 => React.memo로 래핑하여 props를 얕게 비교 가능

  • React.memoPureComponent

  • useRef Hook은 DOM ref뿐 아니라 ref 객체는 현재 프로퍼티가 변경할 수 있고 어떤 값이든 보유할 수 있는 일반 컨테이너로 class의 인스턴스 프로퍼티와 유사

  • 이전 props 또는 state를 얻는 방법

    function Counter() {
      const [count, setCount] = useState(0);
    
      const prevCountRef = useRef();
      useEffect(() => {
        prevCountRef.current = count;
      });
      const prevCount = prevCountRef.current;
    
      return <h1>Now: {count}, before: {prevCount}</h1>;
    }
  • DOM 노드의 위치나 크기를 측정하는 기본적인 방법 - 콜백 ref를 사용

    unction MeasureExample() {
      const [height, setHeight] = useState(0);
    // 콜백 ref를 사용하면 나중에 측정된 노드를 표시하더라도 이에 대한 알림을 받고 측정을 업데이트 가능
      const measuredRef = useCallback(node => {
        if (node !== null) {
          setHeight(node.getBoundingClientRect().height);
        }
      }, []);
    
      return (
        <>
          <h1 ref={measuredRef}>Hello, world</h1>
          <h2>The above header is {Math.round(height)}px tall</h2>
        </>
      );
    }
  • 컴포넌트의 크기가 조정될 때마다 알림을 받으려면 ResizeObserver 사용 가능

  • Effect 외부의 함수 컴포넌트에서 어떤 props 또는 state를 사용하는지 기억하기 어려움
    => 일반적으로 그 내부의 effect에 필요한 함수 컴포넌트를 선언

  • 어떤 이유로 함수를 effect 내부로 이동할 수 없는 경우

    function ProductPage({ productId }) {
      // 모든 렌더링에서 변경되지 않도록 useCallback으로 래핑
      const fetchProduct = useCallback(() => {
        // ... 
      }, [productId]); // 모든 useCallback 종속성이 지정됩니다
    
      return <ProductDetails fetchProduct={fetchProduct} />;
    }
    
    function ProductDetails({ fetchProduct }) {
      useEffect(() => {
        fetchProduct();
      }, [fetchProduct]); // 모든 useEffect 종속성이 지정됩니다
    
    }
  • useMemo를 사용하면 자식의 값비싼 리렌더링 건너뛰기 가능

    function Parent({ a, b }) {
      // 'a'가 변경된 경우에만 다시 렌더링 됩니다:
      const child1 = useMemo(() => <Child1 a={a} />, [a]);
      // 'b'가 변경된 경우에만 다시 렌더링 됩니다:
      const child2 = useMemo(() => <Child2 b={b} />, [b]);
      return (
        <>
          {child1}
          {child2}
        </>
      )
    }
  • 고비용의 객체를 지연해서 생성하는 법

    function Image(props) {
      const ref = useRef(null);
      // IntersectionObserver는 한 번 느리게 생성됩니다
      function getObserver() {
        if (ref.current === null) {
          ref.current = new IntersectionObserver(onIntersect);
        }
        return ref.current;
      }
      // 필요할 때 getObserver()를 호출
    }

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ 파일럿 기간 [~09.28]

📘 API 참고서

  1. React
  2. ReactDOM
  3. ReactDOMClient
  4. ReactDOMServer
  5. DOM 엘리먼트
  6. 테스트 유틸리티
  7. 테스트 렌더러
  8. JS 환경 요구사항
  9. React 기술 용어 모음

🏅 고급 안내서

  1. 접근성
  2. 코드 분할
  3. Context
  4. Error Boundary
  5. Ref 전달하기
  6. Fragment
  7. 고차 컴포넌트
  8. 다른 라이브러리와 통합하기
  9. JSX 이해하기
  10. 성능 최적화
  11. Portal
  12. Profiler
  13. ES6 없이 사용하는 React
  14. JSX 없이 사용하는 React
  15. 재조정 (Reconciliation)
  16. Ref와 DOM
  17. Render Props
  18. 정적 타입 검사
  19. Strict Mode
  20. PropTypes를 사용한 타입 검사
  21. 비제어 컴포넌트
  22. 웹 컴포넌트
profile
Junior Web FE Developer

0개의 댓글