Virtual DOM은 DOM의 가벼운 사본이라 생각할 수 있습니다. DOM은 한 부분이 바뀌면 모든 부분을 리렌더링 하지만 Virtual DOM은 바뀐 부분만 비교해서 그 부분만 렌더링합니다.
용어 정리
DOM - < body > 같은 태그들에 접근하고 조작할 수 있도록 태그들을 트리 구조로 만든 객체 모델
Redux의 기본 개념 : 세 가지 원칙
1. Single source of truth
동일한 데이터는 항상 같은 곳에서 가지고 온다.
즉, 스토어라는 하나뿐인 데이터 공간이 있다는 의미이다.
2. State is read-only
리액트에서는 setState 메소드를 활용해야만 상태 변경이 가능하다.
리덕스에서도 액션이라는 객체를 통해서만 상태를 변경할 수 있다.
3. Changes are made with pure functions
변경은 순수함수로만 가능하다.
리듀서와 연관되는 개념이다.
Store(스토어) – Action(액션) – Reducer(리듀서)
순수함수
동일한 인자가 들어갈 경우 항상 같은 값이 나와야 한다.
return 값으로만 소통한다.
ex) 전달인자 (2,3)
return a + b : 순수함수
return a + b + c : 순수함수 아님 -> c에 의해 결과가 달라지기 때문에 순수함수가 아님
리덕스의 가장 큰 장점 중 하나는 뛰어난 DevTools 지원입니다. 상태 변경, 액션 기록, 시간 여행 디버깅이 가능하여 애플리케이션의 상태를 쉽게 추적하고 디버깅할 수 있습니다.
리덕스 툴킷은 createAsyncThunk와 같은 기능을 통해 비동기 작업을 간편하게 처리할 수 있는 API를 제공합니다
리덕스는 오랜 역사와 큰 커뮤니티를 가지고 있으며, 많은 리소스와 플러그인이 있습니다.
state - State를 생성
값이 변경되면 컴포넌트를 리렌더링한다
ref - Reference 객체를 생성
어떠한 경우에도 리렌더링을 유발시키지 않는다
특정 DOM에 접근이 가능해서 DOM요소를 직접 조작이 가능하다 ex)focus
const refObj = useRef(0)
console.log(refObj) // {current: 0}
const refObj2 = useRef("hi")
console.log(refObj2) // {current: "hi"}
const inputRef = useRef()
<input ref={inputRef} name="인풋"/>
console.log(inputRef.current) // {<input name="인풋">} 직접 접근!
inputRef.current.foucs() // DOM 포커스 하는 함수 사용 가능
current라는 key에 value를 저장하는 것이 기본이다
공통점
컴포넌트 내부의 변수로 활용 가능
제어 컴포넌트 - 사용자의 입력한 값을 useState()로 값을 저장하는 방식, 사용자가 입력한 값이 실시간으로 변하여 항상 최신값을 유지한다.
비제어 컴포넌트 - ref를 이용해 관리, 사용자가 실행해야 값을 변화 시키거나 리렌더링을 일으킨다.
그럼 제어 컴포넌트는 언제 사용할까?
유효성 검사
유효한 데이터가 없는 경우 전송 불가 표시
신용카드와 같은 특정 입력 방식 적용하기
제어 컴포넌트를 사용할 때 문제점?
불필요한 리렌더링, 불필요한 api요청으로 인한 자원 낭비 문제.
이를 막기 위해 디바운싱을 사용할 수 있다.
디바운싱 - 연속적으로 호출되는 함수들 중 마지막 함수(또는 제일 처음)만 호출하도록 하는 것
클래스 형태 컴포넌트에서만 할 수 있었던 state관리나 라이프사이클 등을 함수 형태 컴포넌트에서도 사용할 수 있게 만들어주는 기능입니다.
장점
코드가 간결해진다.
로직의 재사용 가능, 관리가 쉽다
로직을 한 곳으로 모을수 있어서 가독성이 좋다
useEffect, useState등이 있다.
리액트는 자바스크립트 라이브러리로써 싱글 페이지 애플리케이션의 UI(User Interface)를 만드는데 중점을 둔 라이브러리입니다. 리액트는 5개의 특징이 있습니다.
가상돔, 단방향 데이터 바인딩, JSX문법, 선언형 프로그래밍, 컴포넌트 기반이 있습니다.
단방향 데이터 바인딩 - 하나의 Watcher가 자바스크립트의 데이터 갱신을 감지하여 사용자의 UI 데이터를 갱신. 사용자가 UI를 통한 자바스크립트의 데이터를 갱신할 때는, 이벤트를 통해 갱신
양방향 데이터 바인딩 - 사용자 UI의 데이터 변경을 감시하는 Watcher와 자바스크립트 데이터의 변경을 감시하는 Watcher가 UI와 자바스크립트 데이터를 자동으로 동기화 시켜주는 방식
1. useMemo - 리턴되는 값을 Memoization 하는데 사용한다.
Memoization - 이미 계산 해 본 연산 결과를 기억 해 두었다가 동일한 계산을 시키면 다시 연산하지 않고 기억 해 두었던 데이터를 반환 시키는 방법. 시험을 볼 때 이미 풀어본 문제는 다시 풀어보지 않아도 답을 알고 있는 것과 비슷함.
사용 방법
const {newRusult} = useMemo(()=>{... return newResult},[변화 할 값]) // 구조분해할당 사용(안해도됨)
변화 할 값이 변경될때만 콜백 함수가 다시 실행됩니다. 변화 할 값이 변경되지 않으면 함수가 호출한다 해도 변경이 없다 판단되어 이전에 호출한 똑같은 값을 반환합니다. 1번째 인자의 콜백 함수의 return되는 값이 반환된다
2. React.memo - 컴포넌트가 동일하다면 Memoization을 사용합니다.
자식 컴포넌트가 Memoization 됬다고 한다면,
부모 컴포넌트가 리렌더링 되어도 부모에서 전달하는 props가 변하지 않는다면, 자식 컴포넌트는 리렌더링 되지 않는다
더 쉽게 하는법
그냥 export default memo(Component)를 한다.
** exlint 경고가 나올 수 있는데 꺼버리면 된다.
.eslintrc.cjs 파일 => rules: { "react-refresh/only-export-components": "off"}
** 부모에서 선언한 함수를 전해주는 경우
js에서 함수는 주소값이다(객체타입). 그렇기 때문에 부모 컴포넌트에서 자식 컴포넌트로 함수를 전해준다면 부모가 리렌더링 될 때 똑같은 함수를 만들어도 주소값이기 때문에 새로운 함수가 props로 전달되는 것 이다. 이럴 경우 memo가 원하는대로 동작하지 않는다. memo는 얕은비교(===)을 진행하기 때문인다
이럴때 2가지 해결방법이 있는데
export default memo(Components, (prevProps, nextProps) => {
// 반환값에 따라, Props가 바뀌었는지 안바뀌었는지 판단
// T -> Props가 변경되지 않음 -> 리렌더링 x
// F -> Props가 변경됨 -> 리랜더링 o
if(prevProps.id !== nextProps.id) return false;
if(prevProps.contents !== nextProps.contents) return false;
return ture
})
3. useCallback - 함수 선언을 Memoization 하는데 사용된다.
const newFun = useCallback(()=>{},[ 변화할 값 ])
변화할 값이 변경하지 않으면 1번째 인자인 콜백 함수 그 자체를 메모이제이션 하여 반환한다. 즉 1번째 인자가 newFun 이라고 생각하면 된다
4. props로 객체를 넘겨줄 경우 변형하지말고 넘겨주기
5. 컴포넌트를 매핑할 때 key값으로 index를 사용하지 않는다.
6. useState의 함수형 업데이트
7. Input에 onChange 최적화
최적화 대상은 함수나 props를 많이 받는 사용자의 입력값을 받는 대상을 위주로 한다
클래스형 컴포넌트 - state, lifeCycle 관련 기능 사용 가능, 메모리 자원을 더 사용한다.
함수형 컴포넌트 - state, lifeCycle 관련 기능 사용 불가능 [Hook을 통해 해결 됨]
메모리 자원을 덜 사용한다.
클래스형 컴포넌트
import React, {Component} from 'react';
class App extends Component { // class 키워드 필요, Component로 상속을 받아야한다.
render() { // render() 메소드가 반드시 있어야한다.
const name = 'react';
return <div className="react">{name}</div>
}
}
export default App;
함수형 컴포넌트
import React from 'react';
import './App.css';
function App() {
const name = 'react';
return <div className = "react">{name}</div>
}
export default App;
axios의 장점으로는 코드가 간결합니다 또한 CancelToken을 이용해 사용자가 중간에 요청을 취소 할 수 있다는 장점이 있으며, 로그인 로직을 사용할 때 interceptors를 이용해 모든 요청에 JWT 토큰을 자동으로 포함되게 설정할 수 있다는 장점이 있습니다.
accessToken : 짧은 수명의 인증 토큰, 사용자의 ID, 권한, 발급시간 만료시간 등의 정보가 포함된다 서버는 헤더의 accessToken 을 검증하여 신원 확보
로컬스토리지에 저장
refreshToken : accessToken을 재발급받기 위한 용도로 사용되는 긴 수명의 토큰 accessToken이 만료되면 클라이언트는 refreshToken을 서버로 보내 새 accessToken을 요청한다
HTTP-Only 쿠키에 저장
HTTP-Only - javascript 코드로 쿠키에 접근 불가능하다
리덕스가 쥬스탄드나 리코일에 비해 사용하기 좋은 이유는 상태 관리 라이브러리를 사용하는 지표를 보았을때 리덕스가 가장 많이 사용된다. 또한 모든 동작이 리듀서를 통해 이루어 지므로 버그가 적고 리덕스 사가와 리덕스 떵크를 이용해 확장성을 높이기도 좋다
쥬스탄드와 리코일은 가볍고 유연한 상태 관리가 필요한 경우 사용한다
리덕스사가 - yield 키워드를 사용하여 비동기 흐름을 순차적으로 처리할 수 있다
리덕스떵크 - 간단한 비동기 작업 처리를 위해 만들어졌다
가장 큰 차이점은 타입의 확장 가능 여부
타입 - 나중에 쉽게 참조 할 수 있도록 이름을 부여하는 것. 타입에 마우스를 올리면 상세 정보가 나온다
인터페이스 - 새로운 타입 값을 선언하여 ctrl + 클릭을 하면 그 인터페이스로 이동한다. 또한 확장이 가능하다
리액트쿼리 - 데이터 페칭과 상태 관리를 쉽게 하기 위해 사용하는 라이브러리
자동으로 데이터 캐싱을 처리하여 동일한 데이터를 다시 요청하지 않도록 한다.
ex) 사용자가 프로필 페이지에 여러 번 방문하더라도 이미 캐싱된 사용자 데이터가 있으면 서버에 다시 요청하지 않습니다.
비동기 상태 관리 (Loading, Error, Success 상태 관리)를 자동으로 해준다.
리액트 쿼리는 데이터 요청의 로딩 중, 성공, 실패 상태를 자동으로 관리해주기 때문에 코드가 간결해진다.
useQuery - 서버에서 데이터를 읽어오는 경우에 사용. queryKey키가 동일하면 캐싱된 데이터를 사용 아니라면 새로 요청을 보낸다.
useMutation - 새로운 데이터를 생성하거나 기존 데이터를 수정, 삭제하는 비동기 작업을 수행할 때 사용
useInfiniteQuery - 페이지네이션 또는 무한 스크롤을 구현할 때 사용
리액트 - UI를 컴포넌트로 구성하고, JSX를 사용하여 JavaScript와 HTML을 결합합니다. 데이터는 단방향으로 흐른다
뷰 - 템플릿 기반의 선언적 문법을 사용하고, 양방향 데이터 바인딩을 지원 내장 상태 관리 라이브러리인 Vuex를 제공합니다.