TIL

241113 TIL

GoJay 2024. 11. 14. 00:41
  • 토이 프로젝트
    • element.classList.toggle을 해주면 클래스 명이 있으면 없애고, 없으면 추가해 준다. class 이름을 바꿔주고 CSS에서 선택자로 디자인을 다르게 먹여서 토글 이벤트를 만들어낼 때 유용하다.
    • input 창의 type="checkbox"는 이벤트 발생 시 자동으로 checked라는 속성을 추가한다. 만약에 여기서 수동으로 토글 처리를 해주면 아무 이벤트도 일어나지 않는 것처럼 보일 수 있다.
  • React 공식 문서
    • React에서 use로 시작하는 모든 것은 훅(Hook)이다. 훅은 React가 렌더링 중일 때에만 사용할 수 있는 특별한 함수다.
    • 훅은 컴포넌트의 최상위 수준 또는 커스텀 훅에서만 호출할 수 있다. 조건문, 반복문 또는 기타 중첩 함수 내부에서는 훅을 호출할 수 없다.
    • 훅은 함수이지만 컴포넌트의 필요에 대한 무조건적인 선언이다(무슨 얘기인지 이해가 잘 안 된다...).
    • 컴포넌트 내부의 state는 완전히 독립적이다. 같은 컴포넌트를 여러 번 호출해도 각각의 state는 독립이고, 심지어 부모 컴포넌트에서도 자식 컴포넌트의 state를 변경할 수 없다.
    • useState 훅을 이용해 생성한 statesetState를 통해 변경될 시 리액트는 상태의 변화가 있는 컴포넌트를 리렌더링 한다. 즉, state의 변경이 렌더링의 트리거가 되는 것이다.
    • state가 변경되면 상태 변경이 있는 컴포넌트가 반환하는 JSX를 DOM Tree와 비교해서 변경 사항을 반영해 준다. 이 과정을 리액트가 자동으로 처리해 준다.
    • state가 변경되더라도 해당 시점마다 화면을 재렌더링 하는 게 아니다. 아래 코드는 한 번 클릭할 때마다 1씩 증가된다. state0일 때 클릭 이벤트가 일어나더라도 0 + 1, 1 + 1, 2 + 1처럼 순차적으로 계산되어 상태가 변경되는 게 아니라, 렌더링 시점을 기준으로 0 + 1, 0 + 1, 0 + 1이 세 번 호출된다. 그래서 결국 1만 증가된다.
    import { useState } from 'react';
    
    export default function Counter() {
      const [number, setNumber] = useState(0);
    
      return (
        <>
          <h1>{number}</h1>
          <button onClick={() => {
            setNumber(number + 1);
            setNumber(number + 1);
            setNumber(number + 1);
          }}>+3</button>
        </>
      )
    }
    • 해당 값을 실제로 변경하고 싶다면 콜백 함수를 setNumber의 인자로 넘겨주면 된다. 이를 업데이터 함수라고 하며, 업데이터 함수는 렌더링 중에 실행되기 때문에 state를 변경하면 안 되고 순수해야 한다.
      setNumger(number => number + 1);
    • state는 분명 변수와는 다르고 값이 바뀌고 처리되는 프로세스가 상이하다. state는 변경 시 컴포넌트를 다시 랜더링 하고, 랜더링을 기준으로 값의 변화가 정해진다.
    • setTimeout을 걸어도 마찬가지다. 화면에 렌더링이 먼저 완료되더라도, 이벤트가 발생하는 시점의 state 값이 스냅샷으로 관리되기 때문에, 변경되지 않은 원래의 값이 setTimeout 딜레이 안에 적용된다.
    • React는 등록된 이벤트 핸들러의 모든 코드가 완료된 이후에 화면을 리렌더링 한다. 이는 너무 잦은 state 변화로 인해 화면 리렌더링이 많이 될수록 성능에 문제가 생길 수 있기 때문에, 이를 방지하는 방식이다. 이러한 동작을 Batching이라고도 한다.
    • 상태의 변경에 다른 리렌더링 필요 사항을 큐에 저장한다. 큐는 선입 선출이기 때문에 먼저 큐에 들어간 변경 사항이 먼저 반영된다.
    • 참조형 데이터도 state가 될 수 있다. 단, state를 변경할 때 동일한 참조에 내부 프로퍼티 일부만 바꾸는 식으로 처리하는 게 아니라, 아예 새로운 참조형 데이터를 복제해서 변경해야 한다. React는 state가 가리키는 참조가 변경돼야 상태의 변경으로 인식할 수 있는데, 참조형 데이터는 내부의 일부 값이 바뀌어도 스택 메모리 주소는 변하지 않기 때문에다(가변적이기 때문이다). React의 모든 state는 불변으로 처리해야 한다.
    • 참조형 state의 경우 얕은 복사로 처리하면 내부에 있는 참조형 값이 변경되지 않아 state가 제대로 업데이트되지 않을 수 있다. 가급적 깊은 복사를 위한 도구(lodash, immer)를 사용해 깊은 복사 후 처리하자.
    • 보편적인 React 최적화 전략은 이전 props 또는 state가 다음 것과 동일할 때 일을 건너뛰는 방식으로 처리된다.
    • 불필요한 state가 있다면 업데이트하는 것을 잊어버려 버그가 발생하기 쉽다. 주의하자.
    • 때때로 두 컴포넌트의 state가 항상 함께 변경되기를 원할 수 있다. 이를 위해서는 각 컴포넌트에서 state를 제거하고 가장 가까운 공통 부모 컴포넌트로 옮긴 후 props로 자식들에게 전달해야 한다.
    • state의 구조 결정 시 좋은 구조의 근거로 제시된 다섯 가지 원칙이다. state는 '더 단순하게'가 아니라 '가능한 최대로 단순하게' 만들어야 한다.
      • 연관된 state 그룹화하기: 두 개 이상의 state 변수를 항상 동시에 업데이트한다면, 단일 state 변수로 병합하는 것을 고려하세요.
      • State의 모순 피하기: 여러 state 조각이 서로 모순되고 “불일치”할 수 있는 방식으로 state를 구성하는 것은 실수가 발생할 여지를 만듭니다. 이를 피하세요.
      • 불필요한 state 피하기: 렌더링 중에 컴포넌트의 props나 기존 state 변수에서 일부 정보를 계산할 수 있다면, 컴포넌트의 state에 해당 정보를 넣지 않아야 합니다.
      • State의 중복 피하기: 여러 상태 변수 간 또는 중첩된 객체 내에서 동일한 데이터가 중복될 경우 동기화를 유지하기가 어렵습니다. 가능하다면 중복을 줄이세요.
      • 깊게 중첩된 state 피하기: 깊게 계층화된 state는 업데이트하기 쉽지 않습니다. 가능하면 state를 평탄한 방식으로 구성하는 것이 좋습니다.
    • React는 UI 트리에서의 위치에 관심이 있다. UI 트리의 같은 위치에 등록되는 컴포넌트라면 설령 컴포넌트 내부에서 조건에 따라 JSX 리턴 값을 다르게 했더라도 React는 둘을 같은 컴포넌트로 인식한다. UI 트리 상에서의 위치가 같기 때문이다.
    • 때문에, React는 컴포넌트가 같은 위치를 유지하면 state를 유지한다.
  • 인프런 <한 입 크기로 잘라먹는 리액트>
    • props는 부모 컴포넌트에서 자식 컴포넌트로 내려주는 데이터다. 기본적으로 프로퍼티명="값" 형태로 사용되며, 내려갈 땐 { 프로퍼티 명: 값 } 처럼 객체 형태의 데이터가 내려간다.
    • props는 객체이기 때문에 자식 컴포넌트에서 구조 분해 할당으로 필요한 프로퍼티를 직접 가져올 수 있고, 부모 컴포넌트에서 전달할 때 스프레드 연산자(...)를 사용하는 것도 가능하다.
    • 자식 컴포넌트에 컴포넌트.defaultProps를 지정해 주면 props로 내려오는 값들의 default 값을 지정해줄 수 있다. props가 객체의 형태로 내려오기 때문에, defaultProps도 객체로 지정해주면 된다.
    • 부모 컴포넌트에서 자식 컴포넌트를 만들 때 닫는 태그로 닫고(e.g. <Button></Button>) 그 사이에 값을 넣어주면 자식 컴포넌트에는 children 프로퍼티로 값이 내려간다.
    • 컴포넌트에 이벤트 핸들러를 붙일 땐 컴포넌트의 리턴 JSX 구문 안에서 이벤트가 필요한 위치의 태그에 이벤트를 붙여주면 된다. 예를 들면 onClick과 같은 형식이다. 이는 자바스크립트로 이벤트를 처리할 때 HTML 요소를 getElementByquerySelector를 사용해 선택하고 해당 요소에 이벤트를 달아주던 방식과 유사하다.
    • 이벤트로 onClick을 사용했다면, 뒤에는 ={콜백 함수}가 와야한다. 콜백 함수는 해당 위치에서 () => {}와 같이 화살표 함수로 바로 선언해줄수도 있고, 아니면 별도로 지정한 함수를 함수명으로 가져와 사용할 수도 있다.
    • useStatestate와 해당 state를 업데이트 해주는 함수를 반환한다. useState의 인자로 값을 넘기면 state의 초기값이 지정된다. state를 업데이트 해주는 함수는 값이 업데이트 될 시 return 부분을 리렌더링 해주는 역할을 수행한다.
    • useState로 생성한 state가 갖는 특별함은 state의 값을 변경해주는 setState가 호출되면 화면이 다시 렌더링된다는 것이다. 이를 통해 상태를 통한 동적인 화면 전환을 구현하는 게 가능하다.
    • 리액트가 리렌더링 되는 조건은 컴포넌트 자신이 보유한 state가 변하거나, 상위 컴포넌트로부터 받은 props가 변하거나, 부모 컴포넌트가 리렌더링되거나, 이렇게 세 가지다.
  • HTML select 태그
    • 드롭다운 메뉴로 선택지를 만들고 선택하게 하기 위해선 HTML의 <select> 태그를 사용하면 된다.
    • <select> 태그의 하위에 <option> 태그들로 드롭다운 메뉴의 항목들을 넣어주면 UI에 바로 반영된다.
    • 유저들에겐 선택지에 대한 설명을 친절하게 하기 위해 길고 명확한 텍스트를 사용해야 할 수 있다. 하지만, 해당 value를 그대로 받아와 프로그래밍에서 사용하면 효율이 떨어질 수 있다. 그럴 경우, <option> 태그의 value 속성의 값을 지정해주면 지정된 값을 미리 정해둔 값으로 받아와 사용할 수 있다.
    • 예를 들어, <option value="kr">한국</option>이라고 사용하면 '한국'이라는 선택지를 선택할 경우 e.target.valuekr로 들어온다.

'TIL' 카테고리의 다른 글

241116 TIL  (0) 2024.11.17
241114 TIL  (10) 2024.11.15
241112 TIL  (3) 2024.11.13
241109 TIL  (1) 2024.11.10
241108 TIL  (2) 2024.11.09