[CodeStates-Section3]U4.React-상태 관리

hameee·2022년 12월 29일
0

CodeStates_Frontend_42기

목록 보기
29/39

1.후기

Redux라는 라이브러리를 새롭게 배웠다. 상태 관리를 더 편하게 할 수 있다고 하는데 아직은 낯설어서 그런지 React보다 더 어려운 느낌이다. 자주 써먹어서 익숙하게 만들어야겠다.

2.새롭게 알게 된 것

Chapter1. 상태 관리
과제1 - Cmarket Hooks
Chapter2. Redux
과제2 - Cmarket Redux

<Chapter1. 상태 관리>

1.전역 상태 관리

1) Single source of truth(신뢰할 수 있는 단일 출처) 원칙
데이터 무결성을 위해, 동일한 데이터는 항상 같은 곳에서 데이터를 가지고 오도록 함. 즉, 서로 다른 컴포넌트가 동일한 상태를 다룬다면, 이 출처는 오직 한 곳이어야 함. 만일 사본이 있을 경우, 두 데이터는 서로 동기화(sync)하는 과정이 필요한데, 이는 문제를 어렵게 만듦.

2) 전역 상태 관리
ex.
라이트 모드, 다크 모드 테마 설정
국제화(Globalization) 설정
Undo/Redo를 위한 히스토리 기능

3) 상태 관리 툴
React Context
Redux
MobX

4) 상태 관리 라이브러리 장점
-전역 상태를 위한 저장소를 제공
-props drilling 문제를 해결
props drilling(프로퍼티 내려꽂기): 특정 상태가 굳이 필요하지 않음에도 본인의 상위 컴포넌트에서 하위 컴포넌트에게 상태를 넘겨주기 위해 상태를 가지고 있어야 함. 전역 상태 저장소가 있다면 해결 가능

2.Props Drilling

1) Props Drilling이란
상위 컴포넌트의 state를 props를 통해 전달하고자 하는 컴포넌트로 전달하기 위해 그 사이는 props를 전달하는 용도로만 쓰이는 컴포넌트들을 거치면서 데이터를 전달하는 현상

2) Props Drilling의 문제점
-코드의 가독성 하락
-코드의 유지보수 어려움
-state 변경 시 Props 전달 과정에서 불필요하게 관여된 컴포넌트들 또한 리렌더링이 발생
-웹 성능에 악영향

3) 해결 방법
-컴포넌트와 관련 있는 state는 될 수 있으면 가까이 유지하는 방법
-상태관리 라이브러리를 사용하는 방법(전역으로 관리하는 저장소에서 직접 state를 꺼내쓸 수 있음)

<과제1 - Cmarket Hooks>

1.순서

구조 파악(트리 그리기) -> 상태 함수 내려주기 -> 함수 작성

2.트리

3.상태를 내려주는 경우

상태 변경 함수를 활용한 핸들러 작성 시 필요한 경우

4.React 전달 인자, 매개 변수

-전달 인자 작성하는 곳(출발): 이벤트가 발생하는 요소

<button className="cart-item-delete" onClick={() => { handleDelete(item.id) }}>삭제</button>

-매개 변수 작성하는 곳(도착): 이벤트로 인해 실행되는 함수

const handleDelete = (itemId) => {
  setCheckedItems(checkedItems.filter((el) => el !== itemId));
  setCartItems(
    cartItems.filter((el) => {
      return el.itemId !== itemId;
    })
  );
};

-전달 인자, 매개 변수 작성하지 않는 곳
출발, 도착 사이의 넘겨만 주는 태그

<CartItem handleDelete={handleDelete} /><CartItem handleDelete={(itemId) => {handleDelete(itemId)}} />

<Chapter2. Redux>

Redux: React 없이도 사용할 수 있는 상태 관리 라이브러리

1.Redux의 구조

1) 데이터 흐름
Action -> Dispatch -> Reducer -> Store

-상태가 변경되어야 하는 이벤트가 발생하면, 변경될 상태에 대한 정보가 담긴 Action 객체가 생성
-이 Action 객체는 Dispatch 함수의 인자로 전달
-Dispatch 함수는 Action 객체를 Reducer 함수로 전달
-Reducer 함수는 Action 객체의 값을 확인하고, 그 값에 따라 전역 상태 저장소 Store의 상태를 변경
-상태가 변경되면, React는 화면을 다시 렌더링

2.Store

1) 역할
상태가 관리되는 오직 하나뿐인 저장소

2) Store 설정 방법

// <src/index.js>
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Provider } from 'react-redux';// Provider 생성
import { store } from './Store';

const rootElement = document.getElementById('root');
const root = createRoot(rootElement);

root.render(
  // Store를 사용할 컴포넌트를 감싸준 후 Provider 컴포넌트의 props로 store를 설정
  <Provider store={store}>
    <App />
  </Provider>
);

// <src/Store/index.js>
// redux에서 createStore(store 생성 함수)를 불러옴
import { legacy_createStore as createStore } from 'redux';
import { reducder 함수 } from '../Reducers/index.js';

// store 생성, reducer을 store에 연결
const store = createStore(reducer 함수);

3.Reducer

1) 정의
Dispatch에서 전달받은 Action 객체의 type 값에 따라서 상태를 변경시키는 함수.

2) 특징
-순수함수여야 함
-초깃값 지정해야 함, 안 하면 오류(Reducer가 처음 호출될 때 state 값은 undefined)

3) 예시

// <src/Reducers/initialState.js>
// state 초기 상태 설정
export const count = 1

// <src/Reducers/index.js>
import {count} from './initialState.js'

// Reducer를 생성할 때는 초기 상태를 인자로 요구
const counterReducer = (state = count, action) => {

  // Action 객체의 type 값에 따라 분기하는 switch 조건문
  switch (action.type) {

    //action === 'INCREASE'일 경우
    case 'INCREASE':
			return state + 1

    // action === 'DECREASE'일 경우
    case 'DECREASE':
			return state - 1

    // action === 'SET_NUMBER'일 경우
    case 'SET_NUMBER':
			return action.payload

    // 해당하는 경우가 없을 땐 기존 상태를 그대로 리턴
    default:
      return state;
	}
}
// Reducer가 리턴하는 값이 새로운 상태가 됨

4) 여러 개의 Reducer를 사용하는 경우
combineReducers 메서드를 사용

import { combineReducers } from 'redux';

const rootReducer = combineReducers({
  counterReducer,
  anyReducer,
  ...
});

4.Action

1) 정의
어떤 액션을 취할 것인지 정의해 놓은 객체

3) 형식
필수: type -> 대문자, Snake Case(단어 사이의 공백을 밑줄로 대체)
옵션: payload

2) 사용법
-Action 객체를 직접 작성하는 경우

// payload가 필요 없는 경우
{ type: 'INCREASE' }

// payload가 필요한 경우
{ type: 'SET_NUMBER', payload: 5 }

-Action 객체를 생성하는 함수(액션 생성자)를 만들어 사용하는 경우

// payload가 필요 없는 경우
const increase = () => {
  return {
    type: 'INCREASE'
  }
}

// payload가 필요한 경우
const setNumber = (num) => {
  return {
    type: 'SET_NUMBER',
    payload: num
  }
}

3) type 문자열의 변수화 장점
-오타를 방지
-자동완성 기능을 통해 코드 생산성 향상
-코드 재사용하기 용이(예시: Action Creator 함수, Reducer 함수)

4) 예시

// <src/Actions/index.js>
// type 변수 설정
export const INCREASE = 'INCREASE';
export const DECREASE = 'DECREASE';

// 액션 생성자
export const increase = () => {
  return {
    type: INCREASE, // ❌문자열 ✅변수
  };
};

export const decrease = () => {
  return {
    type: DECREASE,
  };
};

5.Dispatch

1) 정의
useDispatch 함수로 생성된 함수

2) 역할
Reducer로 Action을 전달. Action 객체를 전달받은 Dispatch 함수는 Reducer를 호출함.

3) 특징
-전달 인자로 Action 객체를 받음
-이벤트 핸들러 안에서 사용됨.

3) 사용법
객체 자체를 전달해줌
dispatch 함수는 useDispatch를 통해 생성된 함수

// <src/App.js -> App 컴포넌트 -> 이벤트 핸들러 내부>
// Action 객체를 직접 작성하는 경우
dispatch( { type: 'INCREASE' } );
dispatch( { type: 'SET_NUMBER', payload: 5 } );

// 액션 생성자(Action Creator)를 사용하는 경우
dispatch( increase() );
dispatch( setNumber(5) );

6.Redux Hooks

Redux Hooks 메서드는 'redux'가 아니라 'react-redux'에서 불러옴.

1) useDispatch()
Dispatch 함수를 반환하는 메서드

2) useSelector()
컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 메서드

3) 예시

// <src/App.js>
import React from 'react';
import './style.css';
// useSelector, useDispatch import
import { useSelector, useDispatch } from 'react-redux';
import { increase, decrease } from './Actions/index.js';

export default function App() {
  const dispatch = useDispatch();// dispatch 함수 생성
  const counter = useSelector((state) => state);// 컴포넌트와 state 연결

  const plusNum = () => {
    dispatch(increase());
  };

  const minusNum = () => {
    dispatch(decrease());
  };

  return (
    <div className="container">
      <h1>{`Count: ${counter}`}</h1>
      <div>
        <button className="plusBtn" onClick={plusNum}>
          +
        </button>
        <button className="minusBtn" onClick={minusNum}>
          -
        </button>
      </div>
    </div>
  );
}

7.Redux의 세 가지 원칙

1) Single source of truth
의미: 동일한 데이터는 항상 같은 곳에서 가지고 와야 함
관련 Redux 구성 요소: Redux에는 데이터를 저장하는 Store라는 단 하나뿐인 공간이 있음과 연결이 되는 원칙

2) State is read-only
의미: 상태는 읽기 전용이라는 뜻. React에서 상태갱신함수로만 상태를 변경할 수 있었던 것처럼, Redux의 상태도 직접 변경할 수 없음을 의미.
관련 Redux 구성 요소: Action 객체가 있어야만 상태를 변경할 수 있음과 연결되는 원칙

3) Changes are made with pure functions
의미: 변경은 순수함수로만 가능
관련 Redux 구성 요소: 상태가 엉뚱한 값으로 변경되는 일이 없도록 순수함수로 작성되어야 하는 Reducer와 연결되는 원칙

<과제2 - Cmarket Redux>

1.트리

2.Redux 전달 인자, 매개 변수

-전달 인자 작성하는 곳(출발): 이벤트가 발생 태그

<button className = 'cart-item-delete' onClick = {() => {handleDelete(item.id);}}>

-매개 변수 작성하는 곳(도착): 이벤트로 인해 실행되는 함수, action 생성자

// 이벤트로 인해 실행되는 함수
const handleDelete = (itemId) => {
  setCheckedItems(checkedItems.filter((el) => el !== itemId));
  dispatch(removeFromCart(itemId));
};

// action 생성자
export const removeFromCart = (itemId) => {
  return {
    type: REMOVE_FROM_CART,
    payload: {
      itemId,
    },
  };
};

-전달 인자, 매개 변수 작성하지 않는 곳
출발, 도착 사이의 넘겨만 주는 태그

<CartItem handleDelete={handleDelete} /><CartItem handleDelete={(itemId) => {handleDelete(itemId)}} />

0개의 댓글