본문 바로가기

P&P 학회/FRONT-END STUDY

7주차 (2024.11.18)

1. useReducer
useReducer란 react hook들 중 하나로 컴포넌트 내부에 새로운 state를 생성하기 때문에 모든 useState는 useReducer로 대체가 가능하다. useReducer를 이용할 경우, useState와 달리 상태 관리 코드를 컴포넌트 외부로 분리할 수 있다.
 
1.1. useReducer 실기
6주차 프로젝트 업그레이드

 

6주차 (2024.11.11)

프로젝트(투두리스트)1. 프로젝트 준비 [WEB] 리액트 앱 생성 기본 설정1. 파일 생성 후 터미널에서 리액트 앱 생성   2. 기본적으로 필요한 라이브러리들 설치   3. 불필요한 파일 삭제 및 ESLint

nkkim3107.tistory.com

 

useState useReducer
import './App.css'
import { useState, useRef } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';

const mockData = [
  {
    id: 0,
    isDone: false,
    content: "React 공부하기",
    date: new Date().getTime(),
  },
  {
    id: 1,
    isDone: false,
    content: "노래하기",
    date: new Date().getTime(),
  },
  {
    id: 2,
    isDone: false,
    content: "빨래하기",
    date: new Date().getTime(),
  },
];

function App() {
  const [todos, setTodos] = useState(mockData);
  const idRef = useRef(3);

  const onCreate = (content) => {
    const newTodo = {
      id: idRef.current++,
      isDone: false,
      content: content,
      date: new Date().getTime(),
    }

    setTodos([newTodo,...todos]);
  };

  const onUpdate = (targetId) => {
    setTodos(todos.map((todo) =>
      todo.id===targetId
        ? {...todo, isDone: !todo.isDone}
        : todo
      )
    );
  };

  const onDelete = (targetId) => {
    setTodos(todos.filter((todo) => todo.id !== targetId));
  };

  return (
    <div className='App'>
      <Header />
      <Editor onCreate={onCreate} />
      <List
        todos={todos}
        onUpdate={onUpdate}
        onDelete={onDelete}
      />
    </div>
  );
}

export default App
import './App.css'
import { useState, useRef, useReducer } from 'react';
import Header from './components/Header';
import Editor from './components/Editor';
import List from './components/List';

const mockData = [
  {
    id: 0,
    isDone: false,
    content: "React 공부하기",
    date: new Date().getTime(),
  },
  {
    id: 1,
    isDone: false,
    content: "노래하기",
    date: new Date().getTime(),
  },
  {
    id: 2,
    isDone: false,
    content: "빨래하기",
    date: new Date().getTime(),
  },
];

function reducer(state, action) {
  switch(action.type){
    case 'CREATE':
      return[action.data, ...state];
    case 'UPDATE':
      return state.map((item) =>
        item.id === action.targetId
          ? {...item, isDone: !item.isDone}
          : item
      );
    case 'DELETE':
      return state.filter(
        (item) => item.id !== action.targetId
      );
    default:
      return state;
  }
}

function App() {
  const [todos, dispatch] = useReducer(reducer, mockData);
  const idRef = useRef(3);

  const onCreate = (content) => {
    dispatch({
      type: "CREATE",
      data: {
        id: idRef.current++,
        isDone: false,
        content: content,
        date: new Date().getTime()
      }
    })
  };

  const onUpdate = (targetId) => {
    dispatch({
      type: "UPDATE",
      targetId: targetId
    })
  };

  const onDelete = (targetId) => {
    dispatch({
      type: "DELETE",
      targetId: targetId
    })
  };

  return (
    <div className='App'>
      <Header />
      <Editor onCreate={onCreate} />
      <List
        todos={todos}
        onUpdate={onUpdate}
        onDelete={onDelete}
      />
    </div>
  );
}

export default App

 
 

 


 
2. 최적화
최적화란 웹 서비스의 선능을 개선하는 모든 행위를 일컫는다. 

최적화 방법
웹서비스 최적화 React App 내부의 최적화
  • 서버의 응답속도 개선
  • 이미지, 폰트, 코드 파일 등의 정적 파일 로딩 개선
  • 불필요한 네트워크 요청 줄임
  • 컴포넌트 내부의 불필요한 연산 방지
  • 컴포넌트 내부의 불필요한 함수 재생성 방지
  • 컴포넌트의 불필요한 리렌더링 방지

 
2.1. 연산 최적화 (useMemo)
useMemo란 "˚메모이제이션" 기법을 기반으로 불필요한 연산을 제거해 최적화 하는 리액트 훅이다.

자매품: useCallback

최적화 전 최적화 후

 
2.2. React.memo
React.memo란 컴포넌트를 인수로 받아 최적화된 컴포넌트로 만들어 반환하는 것을 뜻한다. 

최적화 전 최적화 후
import './Header.css';

const Header = () => {
    return (
        <div className="Header">
            <h3>오늘은 📅</h3>
            <h1>{new Date().toDateString()}</h1>
        </div>
    );
}

export default Header;
import './Header.css';
import { memo } from 'react';

const Header = () => {
    return (
        <div className="Header">
            <h3>오늘은 📅</h3>
            <h1>{new Date().toDateString()}</h1>
        </div>
    );
}

const memoizedHeader = memo(Header)

export default memoizedHeader;

 
2.3. useCallback

useCallback 사용X useCallback 사용O

 

더보기

++ 추가 스터디: useMemo vs useCallback

메모이제이션: 기존에 연산한 결과값을 메모리에 저장해두고 동일한 입력이 들어오면 재활용하는 기법

useMemo useCallback
메모이제이션 된 '값'을 반환하는 함수

복잡한 계산의 결과를 재사용하여 불필요한 연산을 피한다.
메모이제이션 된 '함수'를 반환하는 함수

컴포넌트가 리렌더링될 때 동일한 함수 객체를 재사용하여 불필요한 재생성을 피한다.
  • 컴포넌트가 리렌더링될 때 동일한 계산을 반복하지 않도록 하고 싶은 경우
  • 특정 값이 변경될 때만 계산을 다시 수행해야 하는 경우
  • 자식 컴포넌트에 함수를 props로 전달하는 경우
  • 함수가 변경되지 않았음에도 자식 컴포넌트가 리렌더링되는 문제를 방지하고 싶은 경우
 import { useState, useMemo } from "react";

 export default function App() {
   const [ex1, setEx1] = useState(0);
   const [ex2, setEx2] = useState(0);
 
   const handleEx1 = () => {
     setEx1((prev) => prev + 1)
   };
   const handleEx2 = () => {
     setEx2((prev) => prev + 1)
   };
 
   useMemo(() => {console.log(ex1)}, [ex1]);

   return (
     <>
       <button onClick={handleEx1}>X</button>
       <button onClick={handleEx2}>Y</button>
     </>
   );
 }
 import { useState, useCallback } from "react";

 function App() {
   const [ex1, setEx1] = useState(0);
   const [ex2, setEx2] = useState(0);
 
   const handleEx1 = () => {
     setEx1((prev) => prev + 1)
   };
 
   const handleEx2 = () => {
     setEx2((prev) => prev + 1)
   };
 
   const returnUseCallback = useCallback(
     () => {console.log(ex2)}, [ex1]);
 
   returnUseCallback();
   
   return (
     <>
       <button onClick={handleEx1}>X</button>
       <button onClick={handleEx2}>Y</button>
     </>
   );
 }

 export default App;
X버튼을 누를 때 콘솔 창에 ex1 값이 출력된다.
Y버튼의 경우, 누르더라도 App 컴포넌트가 전부 리렌더링 되지만 ex1의 값은 변하지 않기 때문에 useMemo에는 아무런 변화가 나타나지 않는다.
Y버튼을 다섯 번 눌렀을 경우, Y버튼이 눌리면 ex2라는 상태 값이 1씩 증가한다. 그러나, 출력 값은 계속 0이다. 이 상태에서 X버튼을 누르면 ex1의 deps가 변하게 되면서
() => {console.log(ex2)를 반환하게 되어 ex2=5일 때의 값을 반환한다. (출력값이 변하지 않았더라도 실제 메모리에서는 ex2의 값이 1씩 증가하고 있었기 때문)

즉, deps가 변해야 함수 컴포넌트와 상태 값(ex2)이 공유된다.

 

참조: https://narup.tistory.com/273

 
 
 
3. Context
ReactJS에서 Context란 컴포넌트 간의 데이터를 전달하는 또 다른 방법으로 기존의 props가 가지고 있던 단점인 props drilling을 해결할 수 있다.
props의 단점: props는 부모 --> 자식 으로만 데이터를 전달할 수 있었음. 즉 계층구조상, 위 컴포넌트에서 두 단계 이상의 컴포넌트에게 다이렉트로 데이터를 전달할 수 없음.
 
3.1. Context 실기
컴포넌트 안 쪽에서 context 객체를 생성하게 되면 문제가 발생하지는 않으나 컴포넌트가 리렌더링 될 때마다 계속 새로운 context를 생성하게 되어 보통 context는 컴포넌트 외부에 선언을 하게 된다.

Context 생성

 

 

 

프로젝트 파일

 

'P&P 학회 > FRONT-END STUDY' 카테고리의 다른 글

8주차 (2024.11.25)  (1) 2024.11.25
6주차 (2024.11.11)  (1) 2024.11.08
5주차 (2024.11.04)  (0) 2024.10.30
4주차 (2024.10.28)  (0) 2024.10.18
3주차 (2024.10.14)  (0) 2024.10.09