
리액트 컴포넌트 종류에는 클래스형, 함수형 컴포넌트가 있습니다. 훅이 나오기 이전에는, 클래스형에서만 상태관리나 생명주기 제어가 가능했는데, 러닝커브가 길고 생명주기 메서드마다 코드를 작성해야 해서 중복코드와 복잡성이 있었습니다. 훅이 등장하면서 함수형에서도 제어가 가능해졌고 코드도 간결해졌습니다.
클래스형에서는 훅을 쓸 수 없습니다. 훅은 함수 호출 순서를 기반으로 상태를 관리하지만, 클래스형은 메서드 중심 구조라 훅의 순서를 추적할 수 없어 지원되지 않습니다.
useEffect는 클래스형의 생명주기 메서드를 대체하기 위해 나온 훅이며 의존성 배열에 따라 최초 한번만 or [ ] 속 상태가 변할 때만 실행됩니다. 실행시점은 화면이 실제로 페인트된 후이므로, 특정 로직에 따라 페이지깜빡임이 발생할 수도 있습니다.
useState는 간단한 상태를 관리할 때는 편리하지만, 상태가 복잡하게 얽히면 로직이 흩어지고 코드가 꼬일 수 있어 복잡한상태일 경우, 관련 상태를 하나의 reducer함수로 로직을 묶어서 관리할 수 있는 useReducer가 적합합니다.
//useState
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const [isOn, setIsOn] = useState(true);
//useReducer
import { useReducer } from "react";
const initialState = { count: 0, step: 1, isOn: true };
function reducer(state, action) {
~ //핵심 로직
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
~
);
}
동기는, 일을 시작 시키고 한 작업(요청/응답)이 끝날 때까지 기다린 후 다음 작업을 진행하고 비동기는, 일을 시작 시키고 그 작업이 끝나길 기다리지않고 다른 작업을 먼저 실행할 수 있습니다. 비동기 처리는 응답 완료 시 실행할 콜백/Promise/async-await이 필요합니다. 비동기 개념이 일반적으로 필요한 이유는 대부분은 서버와의 통신(네트워크 작업)때문입니다. 방식에는 내장함수 fetch나 axios 라이브러리가 있습니다.
// fetch
fetch("/api/info", {
method: "POST",
headers: { "Content-Type": "application/json" }, //헤더
body: JSON.stringify({ name: "다현" }), //바디
})
.then((res) => res.json())
.then((data) => console.log(data));
// axios + async/await
import axios from "axios";
const res = await axios.post("/api/info", { name: "다현" });
console.log(res.data);
fetch
axios
메인에서 분산 처리된 작업을 한개 or 여러개의 스레드에서 처리되느냐로 나눌 수 있습니다.
동시가 당연히 좋을까?
아닙니다. 직렬처리도 반드시 필요한데, 그 이유는 작업 간 순서 보장이 필요할 수 있기 때문이다.
먼저, 비동기와 동시는 같은 개념이 아니다.
비동기는 작업을 보내는 스레드가 응답을 기다릴지말지, 동시는 다른 스레드에 얼마나 분산되어 실행되는지에 초점이 있습니다.
(ex 인스타 돋보기 화면) 서버에서 글이나 이미지를 받아올 때, 스크롤이 버벅거리지 않으려면 네트워크 연산을 여러 스레드로 분산(동시) 처리해야합니다. 성능 반응성이 최적화될 수 있습니다.
(ex 당근마켓 메인 목록 페이지) 목록 페이지를 조회할때는 순서보장이 필요합니다.
프론트 기초 공부 중인데 도움 되네요! 열심히 하시는 것 같아서 저도 동기부여 얻고 갑니다 :)