리액트 개발환경 직접 구축하기

보통 리액트 프로젝트를 시작할 때엔 npm install을 통해서 시작한다.
하지만 이렇게 하는 건 바벨이나 웹팩을 이용해 빌드를 할 때에 사용하는 방법.
바벨과 웹팩 등의 외부 라이브러리가 때로는 리액트를 이해하는 데에 방해가 되기도 한다.

그렇기 때문에, 바벨과 웹팩 없이 순수하게 리액트로만 개발해보는 경험이 필요!

React.useState는 이 파일이 실행될 때 전역변수로 실행이 된다!

createElement

  • UI를 표현하는 가장 작은 단위가 리액트 요소이다
  • 첫번째 인자로 선택한 태그, 두번째 인자로 함수 메소드 및 스타일 등

바벨 사용해보기

  • 자바스트립트 코드를 변환해주는 컴파일러
  • 최신 자스 문법을 지원하지 않는 환경에서도 createElement로
  • react 에서는 JSX 문법을 사용할 때 변환하기위해 사용

npm init -y (패키지 제이슨 파일이 설치됨) npm install @Babel/core @babel/

npx babel

  • 프리셋과 플러그인
    여러개의 플러그인을 특정 목적으로 모아둔 것이 프리셋인 것.

웹팩 사용해보기

  • 다양한 기능 제공

    • 파일 내용을 기반으로 파일 이름에 해시값 추가 => 효율적 프라우저 캐싱 (Vㅏ일 이름 자체가 해시의 키가 된다면 서버에게 ㅇ물어볼 필요가 없은 ㅣ효율적

    • 사용되지 않은 코드 제거
    • Java Script 압축
    • JS, CSS, JSON 텍스트 파일 등 일반 모듈처럼 불러오기
    • 환경 변수 주입
  • 웹팩을 사용하는 가장 큰 이유 => 모듈 시스템을 사용하기 위해서!

export

하나하나로 다 묶어두고, 빼다 쓰는 것을 모듈시스템이라고 한다. export default 를 사용하지 않으면 중괄호로 담아서 import 해야한다! as로 이름을 변경할 수도 있음.

웹팩을 사용하면 변수이름 충돌 등은 빌드단계에서 해결 가능 외브라이브러릴는 npm으로 관리 가능

  • 요즘 브라우저는 ESM을 지원한다. 하지만
    • 오래된 브라우저
    • 많은 오픈소스가 commonJS로 작성됨

==========다른파일

create-react-app(CRA)

리액트 개발환경을 직접 구축하려면 많은 지식과 노력이 필요함.

빌드 시스템 구축을 위해서 웹팩과 바벨 등을 써야하고, 제스트를 이용해서 테스트 환경 구축해야하고, 오래된 브라우저 지원을 위해 polyfill 도 추가를 해야하고, HMR 코드 수정 시 화면에 바로 적용되는 기능과 css 후처리 등도 처리해야함

=> create-react-app이 자동으로 구축해서 제공해준다 !

서버사이드 랜더링의 지원여부

cra는 지원하지 않음! 깔끔한 방법이 아ㅓㅂㅅ다

필수인 프로젝트면 Next/js를 선택해야함.

백오피스처럼 서버사이드 랜더링이 필요없을 때 쓰는 것.

cra는 빌드시스템 변경이 불가능함.

npm start 는 개발모드에서만 써야함. 성능 최적화가 안되어있어서

배포할때는 반드시 build명령어를 써야한다

serviceWorker는 serviceWorker.unresister 되어있기 때문에 아직 동작하지 않음

strictMode는 리액트에서 잘못 사용하는 것을 잡아내기 위해 쓴다.

import logo from ‘~~.svg’이렇게 이미지 해시 값으로 사용하는게 좋다. 브라우저 캐싱을 효율적으로 활용이 가능! 이미지 뿐만 아니라 데이터도 마찬가지. 데이터가 특정 순간에만 필요하다고 할 때에도, 해시값으로 받아오는게 좋다.

    1. 그냥 데이터를 받아오게 해두면, 버튼 클릭하기도 전에 데이터가 있는 상태로 번들이 구성이된다
    1. import로 또 쓰면 파일이 받아와진다

import('./data.json')// 1번의 경우

function onClick() {
  import('./data.json').then({default: data}) => {
    console.log({ data })
  } // onClick 함수안에 담은 2번의 경우
}

npm start로 사용하게 되면 기본적으로http가 실행된다.

https로 실행하고싶다면 HTTPS=true npm start 윈도우는 https로 실행하고싶다면 set HTTPS=true && npm start

빌드하게 되면 정적파일이 생성이 됨. build폴더 안에 있는 정적파일로 서비스만 하면 된는 것. 그러니까 서버사이드 랜더링으로 동작을 할 수 없는 것!

react developer tools 크롬 익스텐션

bulid 명령어 빌드 시 큰이미지는 media폴더 안에 내장되는데, HTTP요청 횟수를 줄이기 위해, 작은 image를 JS파일 내부에 포함한다. (2.0부터는 성능이 좋아져서 그럴 필요는 없긴함) 좀 더 빠르게 이미지를 보여줄 수 있는 장점이 있다.

text 명령어 (test.js를 붙이면 test 파일이 된다.)

eject 명령어

react-scripts를 사용하지 않고 모든 설정파일을 추출하는 명령어 cra를 기반으로 직접 개발환경을 구축하고 싶을 때

추출하지 않으면 cra rㅣ능 추가됫을 때 단순히 버전만 올리는것만 하면 되는데, 추출을 하면 설정파일을 수정을 해버려야하니까 꼭 필요하지 ㅇ낳다면 관리측면에서 추출하지 않는 것이 좋다.

polyfill

IE에서 지원안되는 것을 지원하고 싶을 ㅅ때 사용.

CRA는 기본적으로 core.js가 내장되어있어서 import 만하면 됨. 보통 core.js 를 사용한다.

환경변수란? 환경변수는 개발, 테스트 또는 배포 환경별로 다른 값을 적용할 때 유용하다. 전달된 환경 변수는 코드에서

process.env.{변수이름}

이렇게 사용할 수 있따

CRA는 기본적으로 NODE_ENV라는 값을 가지고 있음. npm start 로 실행하면 .env.development npm test는 .env.test npm build는 .env.production

CSS 작성방법 결정하기

  • 일반적인 css파일 작성
    이름 충돌 문제
  • css 모듈
    module.css 형식으로 작성. 객체 형식이기 때문에 객체로 들어옴 해시값이 붙어서 들어가기때문에, 각 클래스명은 고유값을 가진다. 이름충돌문제 해결! classnames라는 걸 설치하면 좀 더 깔끔하게 작성할 수 있다 cn(Style.button, Style.small)
  • Sass
    node sass를 설치해야함. modulecss와 함께 사용할 수 있음. 변수 사용가능
  • css-in-js
    재사용가능한 구조로 사용할 수 있음! JS안에있는 css
    • styled-components

SPA가 가능하기 위한 조건

  • 자스에서 브라우저로 페이지 전환 요청을 보낼 수 있다
    • Qㅡ라우저는 서버로 요청을보내지 않아야한다
  • 브라우저의 뒤로가기같은 사용자의 페이지 전환 ㄴ요청을 자스에서 처리할 수 있다
    • Qㅡ라우저는 서버로 요청을보내지 않아야한다

위조건은 만족하는 브라우저 API

  • pushState, replaceState 함수
  • popstate 이벤트

JS가 페이지전환을 하고싶을 때, 페이지전환 이벤트를 브라우저에게 알려주는 방법은 pushState, replaceState 함수를 호출하는 것. 반대로 브라우저에서 사용자가 브라우저 UI를 통해서 페이지전환을 하고싶을 때, 페이지전환 이벤트를 JS에게 알려주는 방법은 popstate 이벤트를 통해서 알려준다

onPopState 이벤트를 등록하기위해서 useEffect를 사용했다

SPA는 서버로 요청이 가지 않음!!! 아까 눌렀던 페이지를 기억해서 뒤로가기를 누르면

현재 페이지 이름을 저장하기 위해서 pageName

react-router-dom

페이지별로 코드분할을 위한 react-router-dom

npm install react-router-dom

path정보에 따라 어떤 컴포넌트를 랜더할지 결정한다 (정확성)exact를 넣은 것도 기억. match 안에는 url이 있다. 속성값이 의미하는 것은 path 가 /rooms인데, /rooms/1, /rooms/2, /rooms/3 /rooms는 모두 rooms 컴포넌트가 랜더링이 될텐데, 마지막으로 매치됐던 부분=동일한 프리픽스 url이 /rooms match.url로 이렇게 들어간다. exact 속성을 넣고 match

리액트를 사용한 코드의 특징

button이 가지고 있는 (data-id) dataset 내가 선택한 엘리먼트가 맞는지 확인하고, 맞으면 변경할때 쓰고 삭제하기 위해서 쓰는경우도 있다

이벤트핸들러에서 데이터변경하는 작업만 한다. html은 ui코드도 함께 있다.

비즈니스 로직과 분리가 되어있다.

화면을 어떻게 표현하는지(명령형 프로그래밍) html 화면에 무엇을 그려야하는지(선언형 프로그래밍) react

html, 명령형 프로그래밍은 실행되고 여러이벤트가 발생하면서, ui가 어떤 모습일지 한눈에 보이지않는다. 돔 api를 이용하면 돔환경이 아니면 사용하기 힘들다. react, 선언형 프로그래밍은 무엇을 그릴지만 나타내기 때문에, react는 모바일네이티브의 ui도 표현이 가능

=> react는 추상화단계가 높다. 추상화단계가 높을수록 비즈니스 로직에 집중할 수 있다.

컴포넌트의 속성값과 상탯값

react에서는 UI 데이터를 속성값이나 상태값으로 관리를 한다

react가 변경됐다는 사실을 알기위해서는 상태값으로 관리해야한다.

React.memo 속성값이 변경될 때만 컴포넌트가 랜더링된다.

속성값은 불변이지만 상태는 불변아님. 하지만 상태도 불변변수로 만드는게좋다.

read only 에러! 직접 수정하지 못함.

값을 변경하려면 상태값 변경함수를 사용해야한다.

상태값의 변경은 이전값과의 단순비교로 판단한다. 변경함수로만 해줘야 이전값과 비교해서 변경을 화깅ㄴ하고 랜더를 하는떼. setCount(count)이렇게 직접적으로 하면 이전값이랑 비교가 안됨.

왜 state를 불변으로 해야하는가? 이전 상태값과 비교를 해서 랜더를 해야하기 때문에.

컴포넌트 함수의 반환값

문자열, 숫자, 배열, 컴포넌트, 요소, 프레그먼트,null, boolean…. 모든 것을 반환할 수 있다.

boolean은 조건부 랜더링시 유용

배열로 반환할때는 key요소를 넣어줘야한다.

react가 이 값을 이용해 virtual dom에서의 연산을 편하게 할 수 있다.

프레그먼트(요소의 순서가 키 역할을 해서 key 필요없음)

React Potal은 root 엘러먼트 말고 다른 멀리 떨어진 엘리먼트에 랜더링하고 싶을 때 사용 react-dom에 있는 createPotal 함수 사용

기본적으로 root에다 출력을 하겠다 박아놓기때문에. 그래야 이 react가 이걸 이해한다. 사용된 위치랑 상관없이, 랜더위치를 지정하고 싶을 때 많이 사용한다. (보통 모달을 위해서 많이 사용됨)

리액트 요소와 가상돔

리액트 요소란, 리액트가 UI를 표현하는 방법 빠른 랜더를 위해 돔 변경을 최소화하는것이 좋다. 변경된 부분만 돔에 반영 되는 방식.

리액트 요소 또한 불변 요소. 변경 불가

그런데 상태값을 돔 요소의 key에 넣어버리면? 돔 요소의 key를 변경하면 react는 그걸 다른 요소라고 판단해서 이전것을 삭제하고 새로 만들어서 붙인다.

컴포넌트의 key값을 변경하면 해당 컴포넌트는 삭제(언마운트)됐다가 추가(마운트) 됨

트리는 시간에 따라 변하는 화면의 한 순간을 나타낸다.

리액트 요소가 돔 요소로 만들어지는 과정

랜더단계(가상 돔, 파악 하는 단계) 커밋단계(실제 돔, 파악된 변경사항을 실제돔에 반영하는 단계)

랜더링할때마다 가상돔을 만들고, 실제돔과 비교한다. 실제 돔의 변경사항을 최소화하기 위한 과정

리액스 요소 트리 요소가 실제 돔으로 만들어지기 위해서는, 모든 리액트 요소의 타입 속성값이 문자열이어야한다. 타입 속성값이 문자열인 트리요소가 바로 가상 돔

UI변경된 부분을 빨리찾기위한 개념.

변경되지 않은 부분은 재사용됨.

  1. 랜더함수가 호출되면서 최초의 랜더단계가 실행됨
  2. 이렇게 만들어진 가상 돔이 실제 돔으로 만들어짐
  3. 사용자의 버튼클릭으로 상태값이 변경
  4. 두번째 랜더단계가 실행
  5. 새로운 가상돔이 생성(이전에 가상돔과 비교해서 실제 변경된 부분만 재랜더됨)

  • 컴포넌트 기능 추가할 때 사용하는 함수

    • 상탯값 추가, 자식요소 접근
    • 그전에는 클래스형 컴포넌트
    • 클래스보다 장점이 많고 리액트 팀에서도 훅에서 집중
  • useSTate상탯값 처리
  • useEffect 부수효과 처리(외부의 상태를 변경하는 것)
    • 서버 API 호출, 이벤트 핸들러 등록 등

useState 배열을 반환 효육적으로 처리하기위해 여러개의 상태값변경 요청을 비동기,배치로 처리하기 때문에, 한번만 된다. 동기로 처리하면 하나 호출될때마다 다시 그리기때문에 성능이슈

setCount(count + 1) setCount(count + 1) // 한번만 실행

setCount(v => v + 1) setCount(v => v + 1) // 처리되기 직전의 상탯값을 매개변수로 받기 때문에 원하는대로 처리 가능.

onClick 이벤트핸들러는, 리액트에서 관리하는 리액트요소에 입력되어있기 때문에, 리액트에서 관리하지않는 외부에서 호출하는 경우에는 배치처리한다. onClick(내부)={onClick(외부)}

변경함수는 호출한 순서대로 처리된다.(배치로 처리될때는 별 의미가 없음)

객체로 변경할때는 전체를 입력해줘야한다.

여러상태값을 변경할 때에는 useState보다는 useReducer가 낫다.

모든 부수효과는 useEffect로 관리하는 것이 좋다. 모든 컴포넌트 랜더링 중에 부수효과를 발생시키면 복잡도 크게 증가

이닛텍스트 작서이 힘들어지는 등 순수함수 사용하는 이유 사라짐

컴포넌트 내부에서 직접 실행하는 부수효과가 있으면 한번 랜더링될 때 컴포넌트가 여러번실행될 수 있다. 부수효과 함수

의존성 배열. 값이 변경될 때만 부수효과함수가 실행됨

부수효과함수는 마운트 된 이후에 한번만 호출됨.

부수효과함수의 의존성 배열에는 사용한 변수를 넣음. 지역변수가 있다면 반드시 지역변수도 입력해야한다.

외부함수는 의존성배열에 입력할 필요 없지만, 지역함수를 부수효과 내부에서 사용했다면 지역함수는 입력해야함!

useCallback(메모이제이션이 가능)

부수효과함수가 반환하는 값

언마운트 되기 전에 한번은 호출됨.

사라질때 적어도 한번은

의존성배열을 빈배열로하면!

  • 생성시에만 부수효과함수 호출
  • 사라질때만 반환한(return) 함수 호출

빈배열을 추가하지않으면?

  • 생성시에만 부수효과함수 호출
  • 사라질때만 반환한(return) 함수 호출

없애버리면 상태 변경시마다 이 안에 있는 부수함수든, 반환한 함수든.

커스텀 훅 만들기

랜더만 제외하고 함수를 뚝 떼서, 함수형으로 재사용성이 좋게 한다.

서버사이드 랜더링시에 좋은, 마운트 유무

마운트됐다는건 첫번째 랜더링이 끝났다는 것. 매번호출될 필요는 없으니까 빈배열을 넣는다.

useBlockifNotUser() 로그인된 사용자만 접근할 수 있는 페이지다ㅏ! 저장하지않고 페이지 벗어나려고 하면 저장되지않은 정보가 있다는 알림을 띄우기도 좋음. useBlockUnsavesChange(desc) 이런식으로 상태값을 받아서

로그인유저일때만 실행하고 싶을 때 useEffectIfLoginUser(vallback, deps)

로컬스토리지 토큰 등을 받아서 사용할 때, useLocalStorage(key, initialValue) => [value, setValue]

key로 토큰 등을 받아서 스토리지로 전달시킬 수 있다.

규칙!

  1. 하나의 컴포넌트에서 훅 호출 순서는 늘 같아야한다
      1. if문, for문 등의 안에서 hook을 사용하면 안됨 함수 안에서 사용해도 안된다. 이게 늘 호출된다는 보장이 없으니ㄷ까!
          if(!user) {
         return null;
          }
          const [value, setValue] = useState(1) //안돼!
        

이것도 어쩔땐 호출되고 어쩔땐 안되니까 안됨!

  if(!user) {
    return null;
  }
  return {... }

이렇게 return을 반드시 붙여서 사용해주기.

  1. 훅은 함수형 커뫂넌트 또는 커스텀 훅 안에서만 호출되어야한다.

(그래야 리액트가 훅삳ㅇ태를 제대로 기억할 수 있다.)

hook은 함수형 컴포넌트를 위한 기능!

react는 이렇게, 각 훅이 사용된 위치정보를 기반으로 훅 데이터를 관리한다.

3대 훅!

  • useState
  • useEffect
  • useContext

콘텍스트 API로 데이터 전달하기

상위컴에서 하위컴으로 데이터 전달할때 속성값을 이용한다. 이걸로 충분

근데 많은 수의 하위컴으로 전ㄷ라할때는 반복작업이 힘들다. 중간 컴포넌트에서 기계적으로 전달코드를 작성해야함! 매우 힘들어

createContext

초기값넣어서 호출하면 객체 반환됨. provider와 consumer

호출되면 가장 가까운 Provider를 찾게 됨

찾짐 못해도 초기값이 있기 때문에Provider에서 값을 찾아올 수 있다

하위 모든 consumer는 다시 랜더링된다.

provide의 값을 수정을 해도, 중간에 있는 컴포넌트가 랜더링되지 않고 consumer가 잘 업데이트가 된다.

컨수머 값을 사용했을땐, 컨수머 밖에서는 그 값을 사용할 수 없다.

const userName = useContext(useContext); return <p>{userName}</p>

데이터 종류별로 컨텍스트를 나누면 랜더링에 도움이된다. 하나의 컨텍스트로만 관리하면 하나만 변경되어도 불필요한 다른 부분도 같이 랜더가된다!

하위에서 데이터를 수정하고싶을 때에는?

별도의 함수로 분리하는 방법이 있음.

매번 새로운ㄴ객체가 만들어지지 않도록, 하나의 객체로 관리할 수 이있다.

ref 속성값을 이용한 자식 요소에 접근하기

ㄲef는 일반적인 속성 컴포넌트에도 입력할 ㅅ ㅜ있다.

currrnet 속성은 해당 클래스의 메서드를 호출할수있게 함.

함수형 컴포넌트에서도 내부의 변수와 함수를 노출시킬 수 있다!

React.forwardRef() Eㅜ번째 매개변수로 ref속성값을 받을 수 있다.

useRef를 사용하지 않고, ref속성값에 함수를 사용할 수 있다.

생성시엔 해당요소의 레퍼런스가 넘어오고, 사라질때는 null이 넘어온다.

문자를 입력할 때마다 새롭게 랜더가 되고, 그럼 ref가 있을거고, ref가 있으면 초기텍스트를 넣기때문에 가만히 있는 것.

useCallback 한범 생성된 함수를 계속 재사용!

요소하나마다 useRef를 사용하는게 너무 많을 땐?

ref의 값에 함수를 넣어서 로직으로 처리하는 것.

돔을 직접적으로 선택할 때 사용. 포커스를 주거나, 어떤 작업을 해야할 때 사용한다. 자식 요소에 직접적으로 접근해야할 때.

ref에 current가 없을 경우에는? 생성되기 전에 선택을 해서 ref에 current가 없을 경우가 되게 많다.

그래서 ref속성을 검사하는 코드가 필요하다.

리액트 내장훅

  • useref ref객체는 꼭 돔요소를참조할때만 쓸수있는건 아님. 랜더링과 상관없는 값을 저장할 때, useRef가 유용하게 사용될 수 있음. stateTㅏ용시엔 변경됐을때 랜더링. 하지만 uiEㅔ이터가 아니기때문에 랜더링이 불필요함. ref를 사용하면 변경되어도 랜더링되지 않음!
  • useMemo 함수 메모이제이션 기능. 계산량이 많은 함수의 반환값을 재활용할때에 사용 첫째 매개변수로 함수, 이 함수의 결과 값을 리액트가 기억함. 두번째에 입력한 배열 중 하나의 값이 변경되면 실행. (의존성배열)
  • useCallback 함수 메모이제이션 기능. 함수를 입력해서 속성값으로 전달할 때에는 이 컴포넌트가 랜더링될때마다 새로운 함수가생성되어서 입력 컴포넌트 랜더링이 될 때마다 매번 속성값이 변경되기 때문에, 자식컴포넌트가 불필요하게 랜더됨. useMemo와 마찬가지로 의존성 배열로 관리를 함.
  • useReducer 여러개의 상태값 관리시에 사용하는 것이 좋다. useSTate와 비슷함. 상태값이 반환되고, setState처럼 dispatch가 반환됨. const [state, setState] = useReducer(reducer, INITIAL_STATE);

    redudcer함수는 하단에 현재상태값과 액션이 입력하고, 액션을 보고 상태값을 어떻게 변경할지 판단하는 함수.

    dispath를 호출해서 객체형식으로 입력하면, 그 값이 그대로 액션으로 들어옴.

    useReducer와 contextAPI를 이용하면, 상위컴포넌트에서 트리의 깊은 곳으로 전달할 수 있다.

    useReducer로 상태값을 관리하고 콘텍스트API로 상태값이나 dispatch함수를 내려주는 패턴으로 작성하면 라이브러리없이 리액트만으로도 괜찮은 상태값관리가 된다. (redux로하면 더 잘되겠지만)

  • useImperative

    useImperative함수형 컴포넌트에서도 멤버변수 멤버함수가 있는 것처럼 만들 수 있다. 클래스 컴포넌트에서는 ref객체를 통해 자식 컴포넌트의 메서드를 부모가 가져다쓸 수 있음. 하지만 함수형 컴포넌트에서는 그렇게 못하기때문에, 이걸 사용하면 함수형에서도 가져다쓸 수 있게 할 수 있음!

    ref속성값을 받아서 useImperative의 첫째 매개변수로 입력 useImperative의 둘째 매개변수로 함수 입력. 이 함수가 반환한 값이, 이 부모의 ref 객체가 참조하는 값이 됨.

  • useLayoutEffect effect는 랜더링결과가 반영된 후애 비동기로 동작 이건 부수효과함수를 동기로 처리함! 랜더링결과가 반영된 직후에 바로 처리됨. 부수효과 함수에서 연산을 많이 하면 브라우저가 먹통될 수도 있다. => 특별한 이유가없다면 useEffect를 사용함. 그럼 언제?
    • 랜더링 직후에 돔요소의 값을 읽는경우
    • 조건에따라 컴포넌트를 다시 랜더링하고 싶을 경우

    랜더링, 돔에 반영했지만 브라우저가 화면에 그리기 전에 실행이 됨 (동기)

  • useDebugValue 디버깅시 편리. 리액트 개발자 도구와 함께 쓰면 편리함

가독성과 생산성을 고려한 작성방법.

  • 가장 상단에는 속성값의 타입 정보 컴포넌트 사용하는사람입장에서는 속성값을 올바르게 입력해야함. 작성자입장에서도 속성값을 올바르게 입력해야함. 타입스크립트로도 마찬가지로, 타입을 정의.

  • 함수에 이름을 부여해야한다. 함수에 이름없이 function이라고 하면, 리액트 개발자도구로 디버깅을 할때 찾기 힘들다.

  • props로만 받아서 처리하면 작성 시 불편. 매개변수 문법으로 작성({prop1, prop2})

  • 속성값과 컴포넌트보다 중요도에서 밀리니까 나머지(?)는 하단에 작성.

  • 큰크기의 객체를 생성할때는 컴포넌트 내부에서 말고 외부에서 생성하기. 랜더될때마다 매번 그 객체가 생성됨!

  • useState끼리, useEffect끼리 관리하는 것 보다는 서로 연관된 코드끼리 관리하는게 더 가독성이 좋다.

prop-types

속성값의 타입정보를 입력

자스는 동적타입언어 타입고민업ㅂㅅ이 실행가능 그래서 간단해서 생산성좋음 큰규모 프로젝트에서는 생산성떨어짐. 가능하면 정적타입언어가 좋다. 타스가 인깅ㅆ는 이유 여의치않아서 순수자스를 사용해야할때가 있음. 그럴때 proptypes패키지를 제공

  1. 타입을 지정해서 생산성이 좋다.
  2. 타입정의 자체가 문서가 된다.(굳이 코드를 분석하지않아도 속성값 파악이 가능)

prop-types의 type

  • oneOf
  • oneOfType 타입을배열로 입력
  • arrayOf
  • shape 객체의 타입
  • onjectOf 각 속성의 value의 타입이 number이다

가독성을 높이는 조건부 랜더링 방법

조건부 랜더링을 무분별하게 사용하면 순식간에 복잡해진다!

1만족하는 삼항연산자의 1아닌 2만족하는 삼항연산자의 삼항연산자의 끝에는 null…. 이거 대신 && 연산자로 명확히 구분해주는 것이 좋다.

&& 기호

&& and : true를 만나면 거기서 연산을 끝냄 || or :

(앞에 !!을 두번 붙이면 불리언값으로 전환됨) 또는 null이나 undefined가 아니라고 표현해주면 됨. 빈 문자열인 경우에는 null이나 undefined가 아니기 때문에 뒤에 부분이 잘 나올것이다.

기본값으로 빈배열을 넣는 것이 좋다. 매열인데 undefined가 될수도잇기때문에 앞에 검사하는 코드가 필요함. 내용 && 내용.map 이러케

언마운트되면 상태값이 사라진다. 조건부 랜더링을 수정할때는 리뷰어를 배려하는 마음으로 코드를 작성할 것.

재사용성을 고려한 컴포넌트 구분법

관심사의 분리가 필요! 복잡한 코드를 비슷한 코드기리 묶어서 별도로 관리하는 것. 타입 / API 호출 등 분리

복잡하다면 관심사의 분리가 필요한 순간임.

페이지 별로 폴더별로 관리. 상태값이 컴포넌트의 여기저기에 흩어지고 중복된 것도 많아질 수 있음.

자식에서 부모데이터를 별도의 상태값으로 관리하는건 좋지않다 컴포넌트가 비즈니스로직에 해당하는 상태값을 가지고있으면 재상용하기힘들다

=> 비즈니스 로직상태값의 유무로 컴포넌트를 분리하라

재사용성이 좋은 컴포넌트란?

  1. 비즈니스 로직이 없다
  2. 상태값이 없다(단 UI효과를 위한 상태값은 제외)

useEffect 실전 활용법

가능ㅎ다면 의존성배열 입력하지않는게 좋음. 함수에 상태값으로 관리한는 매개변수가 추가됐는데, 의존성배열에 추가해줘야한다.

부수효과함수로

깜빡하는 걸 위해서 의존성 배열을 찾아줌

변경되지 않는 것이 확실하다면, useEffec로 의존석 없이 쓰는것보다는 명시적으로 훅을 만들어 순서를 명확히 해주ㅈ는 것이 좋다

2가 변경되어서 랜더링이 되어도, 방금생서된 부수효과함수를 무시하고 이전에 1이 생겼을 때의 부수효과함수를 그대로 사용

부수효과함수의 리턴값은 항상 함수만 반환할수있다 그래서 ssync await를 사용할 수 없음 할거면 함수안에 넣어서 호출을 해야함

아래와 같이 배열을 입력하지않는 대신 함수의 실행순서를 부수효과함수 내에서 처리가 가능. => 여기서참조하는 모든 상태값은 최신! 안심. usecallback같은거안써도 됨

useEffect(() => {
if (조건) {
  실행할 함수
}
})

이전상태값을 기반으로 다음 상태값을 계산하기 위해 상태갑승ㄹ 의존성배열에 추가하고 (사진참조).

여러개의 상태값을 변경하며 관리해야할때는 useReducer.

  • useReducer 당ㅇ한 액션과 상태값 관리가 영이, 상태값 변경로직 재사용에도 좋다

의존성배열에 함수를 입력하지 ㅇ낳기 위해

속성값으로 전달되는 함수를 의존성 배열에 넣는순간, 그 함수는 부모컴포넌트에서 useCallback 등을 사영해서 자주변경되지 않도록 신경써서 관리해야한다. (바뀔때마다 부수효과함수를 계속 다시 실행할테니까)

의존성배열이 자주변경되는 문제를 해결하ㅡ는 방법 많음. 내용은 그대로인데 변경될때마다 호출되어서 부수효과함수가 계속 호출됨. => useRef

concurrent mode를 위한 것.

ㄹㅐㄴ더링 속ㄹ 위한 성능 최적화 방법

랜더ㅇ에서 가ㅇ 많ㅣ CPU를 시용함 대부분의 연산을 컴포넌트의 실행과 랜더링에 사용

  • 리엑트 렌더링 과정 컴포넌트(데이터) => 가상돔과 비교 => 실제 돔에 반영

변경점을 찾고, 실제돔에 반영한다.

평상시에는 성능 고민하지 않고 그냥 코딩해라. 대부분 그냥 해도 괜찮다

React.memo 속성값비교함수 랜더링 과정을 생략할 수 있음 이전이후 속성값을 받아서 참,거짓을 반환 참이면 이전 컴포넌트를 그대로 재사용하고 거짓은 실행,가상돔업데이트,변경된 비교만 실제에 반영

만약 속성값 비교함수를 입력하지 않으면, 얕은 비교를 수행하는 기본함수가 사여ㅛㅇ됨

function isEqual(prevProps, nexProps) { //true, false로 반환 } React.memo(MyComponent,isEqual)

React.memo로 감싸지않앗으면 항상 false를 반환하는 함수가 있따고 생각하면 됨

그런데 속성값 변경을 어떻게 판단할까?

객체를 불변데이터로 관리하면, 이전/이후값의 단순비교만으로 데이터 변경을 알 수 있다

const prevTodos = [1,2,3] todo.push(4)

0 === 0 1===1 2===2

이렇게밖에 없는데,

불변데이터로 관리하면 const nextTodos = […todos, 4] prevTodos === nextTodos

이렇게 비교할 수 있다

얕은 비교는 그 안의 속성값끼리 비교를 하는 것.

늘 같은 값을 가지고있다면 밖으로 뺀다.

성능최적화 코드는 가독성이 좋지 않음. 값이 변경되어야하는데 변경되지 않는 경우

set 함수로 변경하는 시점에 랜더링을 일으킨다. push는 그냥 이값에 넘겨주긴하지만 set을 일으킨게 아니다. 그래서 react는 인지를 못해서 랜더링을 안한다!!!

중간에 요소를 추가하면, 그 뒤에 있는 요소가 변경되지 않았다는 것을 일지 못함. 뒤에 있는 변경되지 않은 부분을 다 파악하기 위해서는 모든 부분을 비교해야하는데, 일이 너무 많아짐. 리엑트는 효율적인 랜더링을 위해서 순서정보를 이용한다

그래서 넣는 것이 key! react는 같은 key를 갖는 요소끼리만 비교를 한다

key 속성값은 리엑트가 랜더링을 효율적으로 할 수 있도록 우리가 제공하는 추가정보이다 입력할만한게 없으면 인덱스. 근데 순서를 변경하는 경우에는 비효율적이다

중간에 추가하는 경우에는 key값으로 순서정보가 아닌 id값을 넣어야한다.