[유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 사전직무교육 2주차 후기

2024. 9. 1. 22:44·교육/프로젝트 캠프 : React 2기

 


 

# 0 . 프로젝트 캠프 : React 2기 2주 차 후기

이번주를 마지막으로 총 2주간의 사전직무교육이 마무리되었습니다.
오프라인 9시부터 18시, 점심시간 1시간을 제외하고 풀타임으로 강의를 수강해 본 것이 너무 오랜만이라
빠른 진도를 따라가는 데에만 집중했던 것 같습니다.
3주 차부터는 프로젝트 주차가 시작됩니다.
이번 회고 포스팅에서는 2주 차에 학습했던 내용과 소감을 간단히 다뤄보려고 합니다.

 

# 1 . 프로젝트 캠프 2주 차 요일별 학습 회고

2주 차는 월~목, 총 4일간 사진직무교육을 진행하였으며,
금요일에는 3~6주 차에 예정되어 있는 프로젝트에 대비한 서류작성 및 기업별 킥오프 미팅으로 진행되었습니다.

 

useEffect

useEffect는 컴포넌트가 마운트 될 때, 혹은 의존성배열에 명시한 값의 변동이 있을 때 실행할 코드를 정의할 수 있는 함수입니다.
기본적인 형태는 다음과 같습니다.
// 1. 컴포넌트 마운트(렌더링)시 실행될 코드
// 2. cleanup 함수 : 컴포넌트가 언마운트될때 작성한 코드실행
// 3. 의존성함수,
	// - []내부를 비워두면 마운팅, 렌더링될때마다 useEffect 내부코드 실행
	// - []에 상태값을 넣어두면 해당 상태값이 변경될때마다 useEffect 내부코드 실행

// 기본 형태
useEffect( () => {
	// (1)
    return () => {
    	// (2)
    }	
}, [(3)] );

// 컴포넌트 생성 시점
const compExample = () => {
	useEffect(() => {
    console.log("Component Created");
  }, []);
  return <h1>compExample Component</h1>
}

// 컴포넌트 수정 시점
const compExample = () => {
	const [count, setCount] = useState(0);
	useEffect(() => {
    console.log("Component Count Updated!" + count);
  }, [count]);
  return (
    <h1>{count}</h1>
    <button onClick={() => setCount((count) => count + 1)}>클릭</button>
  )
}

// 컴포넌트 삭제 시점
const compExample = () => {
	useEffect(() => {
    console.log('Component Mounted');
    return () => {
      console.log('Component Unmounted');
    };
  }, []);  
}

useLayoutEffect

useEffect와 동일한 개념이지만 실행되는 방식이 다릅니다.
useEffect는 컴포넌트가 렌더링 된 이후 비동기적으로 실행됩니다.
따라서 DOM을 조작하는 경우에 화면이 깜빡이는 것을 볼 수 있습니다.
하지만 useLayoutEffect는 컴포넌트를 렌더링 하기 직전에 동기적으로 실행되기 때문에
DOM을 조작하는 경우 화면이 깜빡이는 것을 볼 수 없습니다.
import { useEffect, useLayoutEffect, useState } from "react";

const UseLayoutEffect = () => {
  const [count, setCount] = useState(0);
  const now = performance.now();

  // .. 1초정도 딜레이를 유발함
  while (performance.now() - now < 1000) {}

  // .. 0 -> 10 -> 0 의 변화과정이 눈에 보임 ( useEffect )
  //   useEffect(() => {
  //     if (count === 10) setCount(0); // 0 -> 10 -> 0
  //   }, [count]);

  // .. 0 -> 10 -> 0 의 변화과정이 눈에 보이지 않음 ( useLayoutEffect )
  // .. 그래서 언제 사용하는가?
  // .. -> 컴포넌트가 눈에 보여지기 전에 레이아웃의 변경작업을 하고 싶을 때.
  // .. -> DOM을 조작할때 깜박거리는 현상을 보여주고 싶지 않을 때.
  // .. 어떤문제가 있는가? -> useLayoutEffect에 부하가 많이걸리는 작업을 넣으면 이 작업이 동작하는 동안에는 다른작업을 수행할 수 없다.

  useLayoutEffect(() => {
    if (count === 10) setCount(0); // 0 -> 10 -> 0
  }, [count]);

  // 사용처 정리
  // useEffect() : 데이터 통신
  // useLayoutEffect : 레이아웃 변경

  return (
    <>
      <h1>Count : {count}</h1>
      <button onClick={() => setCount(10)}>클릭</button>
    </>
  );
};
export default UseLayoutEffect;

 

 

useTransition

리액트 18 버전에 추가된 동시성 모드를 제공하는 훅입니다.
동시성 모드 : 리액트가 각 작업의 우선순위를 지정하여 동시 다발적으로 처리하는 개념
무거운 작업을 useTransition과 함께 사용하게 되면 부하를 줄이는 효과를 얻을 수 있습니다.
const [pending, startTransition] = useTransition();

 

useDeferredValue

const deferredDummy = useDeferredValue(value);
리액트 18 버전에 추가된 동시성 모드를 제공하는 훅입니다.
useTransition과 비슷하게 무거운 작업과 함께 사용하였을 때 부하를 줄여 렉을 감소시킬 수 있습니다.

 

useTransition vs useDeferredValue

두 개의 훅 모두 작업의 우선순위를 낮추어 처리함으로써 렉을 감소시킨다는 효과가 있습니다.
하지만 useTransition은 함수를, useDeferredValue는 값을 처리한다는 점이 다릅니다. ( 대상이 다름 )
그러므로 처리해야 하는 작업이 어떠한 형태인지 파악하고 알맞게 사용하는 것이 좋습니다.

 

useCallBack

함수형 컴포넌트를 메모이제이션하는데 사용되는 훅입니다.
메모이제이션이란 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때,
이전에 계산한 값을 메모리에 저장하여 사용함으로써 동일한 계산의 반복수행을 제거하여,
프로그램의 실행속도를 향상시키고 성능을 개선하는 기술을 말합니다.
// 기본 형태
const fnExample = useCallback(함수, [의존성배열])

// 상세 내용
// increment, decrement는 참조자료형
// -> 리렌더링 될 때마다 새로운 값이 되어버린다.
// -> 그래서 메모이제이션이 되지 않는 것
// -> 참조자료형을 매개변수로 받는 컴포넌트는 React.memo를 통해서 메모이제이션 되지 않는다.

// 따라서 useCallBack으로 메모이제이션 해줘야한다.

// useCallBack이 메모이제이션의 풀어지는 조건은
// 의존성 배열에 있는 값이 변하는 것.
// -> 의존성 배열을 비워둔다면 절대 풀어지지 않는다.

const increment = useCallback(() => {
  setCount((count) => count + 1);
}, []);

const decrement = useCallback(() => {
  setCount((count) => count - 1);
}, []);

// 함수는 콜백형태로 작성해야만 한다
// 콜백형태로 작성하지않으면 메모이제이션 되었을때의 값을 기억하기때문에
// .. 정상적으로 동작하지 않는다.

useMemo

값을 메모이제이션하는데 사용하는 훅입니다.
// 기본 형태
const valueExample = useMemo(값, [의존성배열])

// 상세 내용
import { useMemo, useState } from "react";
import { initialItems } from "../../utils/utils";

const UseMemo = () => {
  // 의도적으로 부하를 줄 수 있는 값을 정의합니다.
  const [items] = useState(initialItems);
  const selectedItems = useMemo(() => items.find((item) => item.selected), []);
  const [count, setCount] = useState(0);
  return (
    <>
      <h1>UseMemo Component</h1>
      <pre>{JSON.stringify(selectedItems, null, 2)}</pre>
      <h1>count : {count}</h1>
      <button onClick={() => setCount((count) => count + 1)}>증가</button>
    </>
  );
};
export default UseMemo;

 

React.memo

컴포넌트를 메모이제이션하는데 사용하는 훅입니다.
export default React.memo(대상컴포넌트);

 

useReducer

조금 더 복잡한 상태관리를 할 때 사용하는 리액트 훅입니다
넓은 범위에서 useState 훅과 비슷합니다.
// 기본 형태
const [state, dispatch] = useReducer(reducer, initialState);

// 예제 코드
import { useReducer } from "react";
import "./Counter.css";

const reducer = (state: number, action: { type: string }) => {
  switch (action.type) {
    case "increament":
      return state + 1;
    case "decreament":
      return state - 1;
    default:
      return state;
  }
};

const Counter = () => {
  const [counter, dispatch] = useReducer(reducer, 0);
  return (
    <div className="counter">
      <h1>{counter}</h1>
      <div>
        <button onClick={() => dispatch({ type: "decreament" })}>-</button>
        <button onClick={() => dispatch({ type: "increament" })}>+</button>
      </div>
    </div>
  );
};

export default Counter;

 

ContextAPI

데이터가 필요한 컴포넌트가 직접 데이터를 요청하고 받는 방식
context 사용방법
  1. context 공급자 생성 - createContext( );
  2. 공급자 범위를 지정한다 → 생성한 공급자 컴포넌트의 객체의 몬텐츠로 공급할 다른 컴포넌트를 감싼다
  3. 공급할 데이터를 value 속성으로 지정
  4. 공급할 데이터를 useContext(공급자 컴포넌트 계획)로 받아서 사용한다.

 

Zustand

전역 상태 관리의 대표적인 라이브러리입니다.
카운터 상태를 관리하는 store를 정의합니다.
store에서 원하는 데이터를 받아서 사용할 수 있습니다.
import { create } from 'zustand';

const useCounterStore = create((set) => ({
  count: 0,
  increase: () => set((state) => ({ count: state.count + 1 })),
  decrease: () => set((state) => ({ count: state.count - 1 })),
}));

export default useCounterStore;

// ------------------------------------------------------------

// App.js
import React from 'react';
import useCounterStore from './counterStore';

function App() {
  const { count, increase, decrease } = useCounterStore();

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increase}>Increase</button>
      <button onClick={decrease}>Decrease</button>
    </div>
  );
}

export default App;
공식사이트 첫 화면 예제에서는 구조분해할당하는 것으로 사용되었습니다.
하지만 documentation에 명시된 방법이 더 권장되는 방법입니다.
자세한 코드는 다음과 같습니다.
// 공식 홈페이지 첫화면 예제
// - 구조분해할당
import { create } from 'zustand'

const useStore = create((set) => ({
  count: 1,
  inc: () => set((state) => ({ count: state.count + 1 })),
}))

function Counter() {
  const { count, inc } = useStore()
  return (
    <div>
      <span>{count}</span>
      <button onClick={inc}>one up</button>
    </div>
  )
}

//-------------------------------------------------------------------------

// 공식 홈페이지 documentation 예제
// - create a store
import { create } from 'zustand'

const useStore = create((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  removeAllBears: () => set({ bears: 0 }),
  updateBears: (newBears) => set({ bears: newBears }),
}))

// - binding components
function BearCounter() {
  const bears = useStore((state) => state.bears)
  return <h1>{bears} around here...</h1>
}

function Controls() {
  const increasePopulation = useStore((state) => state.increasePopulation)
  return <button onClick={increasePopulation}>one up</button>
}

 

Data Fetching

일반적인 fetch API를 사용하여 데이터 통신하는 방법에 대해 다뤄봤습니다.
// 리액트에서 API를 통해 데이터를 fetching하는 가장 기본적인 방법
useEffect(() => {
  fetch("https://jsonplaceholder.typicode.com/todos/1")
    .then((response) => response.json())
    .then((json) => setTodo(json));
}, []);

 

 

data fetching + loading 상태에 따른 조건부 렌더링 1 
// 1. 데이터를 불러오는 방법
// 2. 로딩상태를 핸들링하는 방법

import { useEffect, useState } from "react";

const FetchBasic = () => {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  // 리액트에서 API를 통해 데이터를 fetching하는 가장 기본적인 방법
  useEffect(() => {
    setIsLoading(true); // 로딩상태 true
    fetch("http://localhost:5000?t=5000")
      .then((response) => response.json())
      .then((json) => {
        setData(json);
        setIsLoading(false);
      });
  }, []);

  if (isLoading) {
    // 로딩중일때 수행할 작업
    return <h1>Loading</h1>;
  }

  return (
    <>
      <h1>FetchBasic Component</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </>
  );
};
export default FetchBasic;

 

data fetching + loading 상태에 따른 조건부 렌더링 2
// 위 예시와 다른점
// : 아래코드는 특정부분만 조건부렌더링이 가능하다.
// : 하지만 위 코드는 loading상태라면 화면전체에 Loading만 렌더링된다.
import { useEffect, useState } from 'react'

const FetchBasic = () => {
    const [data, setData] = useState(null);
    const [isLoading, setIsLoading] = useState(false);

    // 처음 화면 렌더링시에만 데이터를 fetching한다.
    useEffect(() => {
        setIsLoading(true);
        // fetch('https://jsonplaceholder.typicode.com/todos')
        fetch('http://localhost:3000?t=3000')
            .then(response => response.json())
            .then((json) => {
                setData(json);
                setIsLoading(false);
            })
    }, [])
    return (
        <>
            <h1>FetchBasic</h1>
            {/* isLoading이 true면 Loading 출력
            false면 fetching된 데이터 출력 */}
            {
                isLoading
                    ? <h1>Loading...</h1>
                    : <pre>{JSON.stringify(data, null, 2)}</pre>
            }
        </>
    )
}
export default FetchBasic

 

 

data fetching + 에러 핸들링
import React, { useEffect, useState } from 'react'

const FetchBasic = () => {
    const [data, setData] = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("")
    const [isError, setIsError] = useState(false);

    // 처음 화면 렌더링시에만 데이터를 fetching한다.
    useEffect(() => {
        setIsLoading(true);
        fetch('http://localhost:3000?t=3000')
            .then(response => response.json())
            .then((json) => {
                setData(json);
                setIsLoading(false);
            }).catch((e) => {
                setIsLoading(false);
                setIsError(true);
                setError(e instanceof Error ? e.message : "알 수 없는 에러");
            })
    }, [])

    if (isError) {
        return <h1>{error}</h1>
    }

    return (
        <>
            <h1>FetchBasic</h1>
            {/* isLoading이 true면 Loading 출력
            false면 fetching된 데이터 출력 */}
            {
                isLoading
                    ? <h1>Loading...</h1>
                    : <pre>{JSON.stringify(data, null, 2)}</pre>
            }
        </>
    )
}
export default FetchBasic

 

 

data fetching + API요청이 끝나기 전 사용자가 이탈하는 경우 핸들링
import React, { useEffect, useState } from 'react'

const FetchBasic = () => {
    const [data, setData] = useState(null);
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("")
    const [isError, setIsError] = useState(false);

    // 처음 화면 렌더링시에만 데이터를 fetching한다.
    useEffect(() => {

        const controller = new AbortController();
        const signal = controller.signal;

        setIsLoading(true);
        setIsError(false);

        // fetch('https://jsonplaceholder.typicode.com/todos')
        fetch('http://localhost:3000?t=3000', { signal })
            .then(response => response.json())
            .then((json) => {
                setData(json);
                setIsLoading(false);
            })
            .catch((e) => {
                if (e.name === "AbortError") return; // API요청이 취소된것일뿐 에러가 아니다라는 처리
                setIsLoading(false);
                setIsError(true);
                setError(e instanceof Error ? e.message : "알 수 없는 에러");
            })
            .finally(() => {
                // 성공, 실패와 관계없이 무조건 실행
                setIsLoading(false);
            })

        return () => {
            controller.abort();
        }
    }, [])

    if (isError) {
        return <h1>{error}</h1>
    }

    return (
        <>
            <h1>FetchBasic</h1>
            {/* isLoading이 true면 Loading 출력
            false면 fetching된 데이터 출력 */}
            {
                isError && <h1>{error}</h1>
            }
            {
                isLoading
                    ? <h1>Loading...</h1>
                    : <pre>{JSON.stringify(data, null, 2)}</pre>
            }
        </>
    )
}
export default FetchBasic

 

# 2 . 사전직무교육 2주 차 수강 후기

2주 차는 본격적인 리액트 훅과 데이터 통신에 대한 개념을 학습하고 관련된 실습을 여러 차례 진행하였습니다.

이전에 리액트를 학습하며 어려웠거나 몰랐던 부분들을 한번 더 공부함으로써 정리할 수 있는 시간이었고
강의자체가 속성으로 중요내용만 빠르게 짚고 실습하는 방식이라 학습하는 데에도 도움이 많이 되었습니다.

강사님께서 최근에 수강했던 인터넷강의들에 비해 훨씬 잘 가르쳐주셔서 꽤나 만족했었던 2주였습니다.
강의자료나 퍼블리싱자료에도 많은 공을 들였다고 하셨는데,
그런 부분이 느껴질 정도여서 더 수월하게 이해하고 학습했던 것 같습니다.

2주안에 많은 개념을 다뤘고 많은 실습을 진행하였습니다.
실습 분량이나 많고 난이도가 쉽지만은 않은 만큼 한 번만 공부하고 넘기기에는 무리가 있을 것 같습니다.
추가적인 공부 및 실습을 통해 여러 번 정리해서 능숙하게 다룰 수 있도록 해야겠습니다.

 

# 3. 프로젝트 주차를 준비하며..

다음주, 9월 2일부터 프로젝트 주차가 시작되어 사전에 정해진 팀원분들과 협업하여 프로젝트를 진행하게 됩니다.

킥오프미팅 때 기업에서 언급해 주신 주요 구현사항에 집중하여 어떤 기술을 프로젝트에 녹여낼지와 같은 상세 내용들을 팀원분들과 미팅을 진행하여 우선적으로 결정하고 프로젝트를 세팅하는 한 주가 될 것 같습니다.

프로젝트 협업은 경험이 있으나 그때는 git이나 notion을 잘 다루는 분들이 세팅해 주셔서 따라가기만 했었는데,
이번기회에는 찾아서 공부해 보고 직접 적용해보려고 합니다. 

팀원들끼리 서로서로 부족한 부분을 채워주면서 4주 동안의 프로젝트가 문제없이 잘 진행되었으면 좋겠습니다.

 

 

 


 

본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 과정(B-log) 리뷰로 작성 되었습니다.

 #udemy #웅진씽크빅 #스나이퍼팩토리 #인사이드아웃 #미래내일일경험 #프로젝트캠프 #부트캠프
#React #리액트프로젝트 #프론트엔드개발자양성과정 #개발자교육과정

반응형
저작자표시 비영리 변경금지 (새창열림)

'교육 > 프로젝트 캠프 : React 2기' 카테고리의 다른 글

[유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 프로젝트 코스 3주차 후기  (2) 2024.09.22
[유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 프로젝트 코스 2주차 후기  (6) 2024.09.16
[유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 프로젝트 코스 1주차 후기  (1) 2024.09.08
[유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 사전직무교육 1주차 후기  (5) 2024.08.25
'교육/프로젝트 캠프 : React 2기' 카테고리의 다른 글
  • [유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 프로젝트 코스 3주차 후기
  • [유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 프로젝트 코스 2주차 후기
  • [유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 프로젝트 코스 1주차 후기
  • [유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 사전직무교육 1주차 후기
heee1
heee1
FE 개발자를 희망하는 임희원 입니다.
  • heee1
    heee1.blog
    heee1
  • 전체
    오늘
    어제
    • 분류 전체보기 (69)
      • Front-end (1)
        • Javascript (4)
        • Typescript (1)
        • React (0)
        • Next.js (1)
        • Tool (1)
        • Git (1)
        • Prettier (0)
        • Test-Framework (1)
        • Vercel (1)
      • 교육 (28)
        • 항해99 : 웹개발 종합반 18기 (14)
        • 프로젝트 캠프 : React 2기 (5)
        • 코드잇 스프린트 : 단기심화 5기 (9)
      • Algorithm (29)
        • Javascript (24)
        • Python (5)
      • 코드 보관함 (1)
        • 배치스크립트 ( .bat ) (1)
  • 블로그 메뉴

    • 홈
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    react-spring
    항해99
    티스토리챌린지
    자바스크립트
    next.js
    코드잇
    til
    jest
    speed insights
    JavaScript
    tailwindcss
    Baekjoon
    Python
    모킹
    스프린트
    백준
    오블완
    node.js
    css animation
    테스트 프레임워크
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
heee1
[유데미x스나이퍼팩토리] 프로젝트 캠프 : React 2기 - 사전직무교육 2주차 후기
상단으로

티스토리툴바