본문 바로가기
  • GDG on campus Ewha Tech Blog
3-1기 스터디/Front-End 토이 프로젝트

[9주차] Context API, 리덕스 라이브러리 이해하기

by ssine 2022. 1. 30.



GDSC FE-Toy Project Study Plan

  • 'React를 다루는 기술' Ch15, 16 공부 및 실습 진행

 

[Week 9] 1/13

  • 발표자
    • Ch15. Context API - 장아연
    • Ch16. 리덕스 라이브러리 이해하기 - 장효신

 

✔ 전역 상태 관리 흐름 이해

  • 여러 컴포넌트를 거쳐 props 사용 시 기존의 top->bottom 흐름으로 많은 컴포넌트 거치거나 데이터가 많아지는 경우 유지 보수성 낮아짐
  • Context 만들어 한번에 원하는 값 받아옴

✔ Context API 사용법

1. 새로운 Context 생성

  • createContext 함수를 사용해 Context 생성
  • 파라미터로 해당 Context 기본 상태 지정
import {createContext} from "react";
const ColorContext=createContext({color:"black"}); //기본 상태 색상 : 검정
export default ColorContext;

2. Consumer 사용

  • ColorBox 컴포넌트 만들어 ColorContext 안에 있는 색상 불러옴
  • props가 아닌 ColorContext 안에 Consumer 컴포넌트 사용
  • Render Props : Consumer 사이에 중괄호 열어 그 안에 함수 넣음
import React from 'react';
import ColorContext from '../contexts/color';

const ColorBox=()=>{
    return (
        <ColorContext.Consumer>
            {value =>(
                <div style={{width:"64px", height:"64px", background:value.color}}/>
            )}
        </ColorContext.Consumer>
    );
};

export default ColorBox;

3. App에서 랜더링

import './App.css';
import ColorBox from './component/ColorBox';

const App=()=>{
  return (
    <div>
      <ColorBox/>
    </div>
  );
};

export default App;

4. Provider 사용

  • Provider 사용해 Context의 value 변경
  • Provider 사용하고 value 명시 안하면 오류 발생
import logo from './logo.svg';
import './App.css';
import ColorBox from './component/ColorBox';
import ColorContext from './contexts/color';

const App=()=>{
  return (
    <ColorContext.Provider value={{color:"red"}}> 
    {/*provider를 사용한 value 변경*/}
      <div>
        <ColorBox/>
      </div>
    </ColorContext.Provider>
  );
};

export default App;

✔ 동적 Context 사용

1. 함수 전달하는 Context

  • 새로 작성한 ColorProvider 컴포넌트에 ColorContext.Provider 랜더링
  • Provider의 value에 상태(state), 업데이트 함수(actions) 분리해서 묶어서 전달하면 다른 컴포넌트에 Context 값 사용할 때 편함
import {createContext, useState} from "react";

const ColorContext=createContext({
    state:{color:"black", subcolor:"red"},
    actions:{
        setColor:()=>{},
        setSubcolor:()=>{}
    }
});


const ColortProvider=({children})=>{
    const [color,setColor]=useState("black");
    const [subcolor,setSubcolor]=useState("red");

    const value={
        state:{color,subcolor}, //상태
        actions:{setColor,setSubcolor} //업데이트 함수
    };

    return (
      //상태와 업데이트 함수 따로 분리하여 작성하여 
      //ColorContext.Provider에 넣는 객체의 형태와 일치 하는 것이 좋음
      <ColorContext.Provider value={value}>
      	{children}			
	</ColorContext.Provider>);
};

//const ColorConsumer =ColortContext.Consumer
const {Consumer:ColorConsumer}=ColorContext;

//ColorProvider와 ColorConsumer 내보내기
export {ColortProvider,ColorConsumer};

export default ColorContext;

2. 새로운 Context 프로젝트 반영

  • App 컴포넌트에서 ColorContext.Provider -> ColorProvider
import './App.css';
import ColorBox from './component/ColorBox';
import { ColortProvider } from './contexts/color';

const App=()=>{
  return (
    <ColortProvider>
          <div>
        <ColorBox/>
      </div>
    
    </ColortProvider>
  );
};

export default App;
  • ColorBox 컴포넌트에서 ColorContext.Consumer -> ColorConsumer
  • 객체 비구조화 할당 문법 사용해 value.state.color -> state.color
import React from 'react';
import { ColorConsumer } from '../contexts/color';

const ColorBox=()=>{
    return (
        <ColorConsumer>
            {({state})=>(
                <>
                    <div
                        style={{width:"64px", height:"64px",background:state.color}}/>
                    <div 
                        style={{width:"32px", height:"32px", background:state.subcolor}}/>
                </>
            )

            }

        </ColorConsumer>
    );
};

export default ColorBox;

3. 컬러 선택 팔레트 UI

import React from 'react';

const colors=["red","orange","yellow","green","blue","indigo","violet"];

const SelectColors=()=>{

    return (
        <div>
            <h2> 색상을 선택하세요.</h2>
            <div style={{display:"flex"}}>
                {colors.map(color=>(
                    <div key={color}
                    style={{
                        background:color,
                        width:"24px",
                        height:"24px",
                        cursor:"pointer"
                    }}/>
                ))}
            </div>
            <hr/>
        </div>
    );
};

export default SelectColors;
import './App.css';
import ColorBox from './component/ColorBox';
import { ColortProvider } from './contexts/color';
import SelectColors from './component/SelectColors';

const App=()=>{
  return (
    <ColortProvider>
        <div>
          <SelectColors/>
          <ColorBox/>
      </div>
    
    </ColortProvider>
  );
};

export default App;

4. 컬러 팔레트 클릭으로 색상 변경

  • 마우스 왼쪽 클릭 : 큰 정사각형 색상 변경
  • 마우스 오른쪽 클릭 : 작은 정사각형 색상 변경
import React from 'react';
import { ColorConsumer } from '../contexts/color';

const colors=["red","orange","yellow","green","blue","indigo","violet"];

const SelectColors=()=>{

    return (
        <div>
            <h2> 색상을 선택하세요.</h2>
            <ColorConsumer>
            {({actions})=>(

                <div style={{display:"flex"}}>
                    {colors.map(color=>(
                        <div
                            key={color}
                            style={{background:color,width:"24px", height:"24px",cursor:"pointer"}}

                            //마우스 왼쪽 클릭 : 큰 정사각형 색상 변경
                            onClick={()=>actions.setColor(color)}
                            
                            //마우스 오른쪽 클릭 : 작은 정사각형 색상 변경
                            onContextMenu={e=>{
                                e.preventDefault();
                                //마우스 오른쪽 버튼 클릭 시 메뉴가 뜨는 것을 무시
                                actions.setSubcolor(color);
                            }}
                        />
                    ))}
                </div>
                )}
            </ColorConsumer>
            <hr/>
        </div>
    );
};

export default SelectColors;

Ch 16. 리덕스 라이브러리 이해하기

1) 리덕스란?

npm trends 최근 1년간 다운로드 수

  • 가장 많이 사용하는 리엑트 상태 관리 라이브러리
    • 그 외 MobX, Recoil, Context API, useSWR, react-query, apollo
  • 컴포넌트의 상태 관련 업데이트 로직을 다른 파일로 분리시켜서 효율적으로 관리할 수 있음
  • 컴포넌트에서 똑같은 상태를 공유해야 할 때, 여러 컴포넌트를 거치지 않고 상태 값을 전달/업데이트할 수 있음
  • 단순히 전역 상태관리만 한다면 Context API를 사용하는 것만으로도 충분하지만, 리덕스를 사용하면 상태를 더욱 체계적으로 관리할 수 있기 때문에 프로젝트 규모가 클 경우 리덕스 사용 추천
  • 장점
    • 코드의 유지 보수성 높여줌
    • 작업 효율 극대화 해줌
    • 개발자 도구 지원 (Redux DevTools)
    • 미들웨어 기능 제공(Redux-thunk, Redux-saga). 비동기 작업을 효율적으로 관리할 수 있음

2) 리덕스 개념 정리

리덕스를 사용하면서 만나게 될 키워드 5가지

  • 액션
  • 스토어
  • 디스패치
  • 리듀서
  • 구독

액션

액션은 상태 변화를 일으킬 때 참조하는 객체로 상태에 어떤 변화가 필요할 때 액션 발생함

형식

하나의 객체로 표현됨

{
 type: 'TOGGLE_VALUE', // 반드시 있어야 함
 data: { // 마음대로 넣을 수 있음
  id: 1,
  text: '리덕스 배우기'
  }
}

이 액션 객체는 반드시 type 필드를 가지고 있어야 함

type의 값은 액션의 이름

그 외의 값은 나중에 상태를 업데이트할 때 참고해야 할 값으로 마음대로 넣을 수 있음


액션 생성 함수

액션 객체를 만들어주는 함수

function addTodo(data){
	return {
     type: 'ADD_TODO',
     data
    };
}

// 화살표 함수로도 만들 수 있음 (추천)
const changeInput = text => ({
 type: 'CHANGE_INPUT',
 text
});

사용 목적

  • 변화를 일으킬 때마다 액션 객체를 만들어야 하는데 매번 액션 객체를 작성하기는 번거롭고 만드는 과정에서 실수할 수 있음
  • 이러한 일을 방지하기 위해 함수로 만들어서 관리함

리듀서

리듀서는 실제로 변화를 일으키는 함수

 

순서

1. 액션을 만들어서 발생시킴

2. 리듀서가 현재 상태와 전달 받은 액션 객체를 파라미터로 받아옴

3. 두 값을 참고해서 새로운 상태 반환

 

const initialState = {
 counter: 1
};

// state값이 undefined면 initialState를 참조함
function reducer(state=initialState, action) {
 switch(action.type){
  case INCREMENT:
   return {
    counter: state.counter + 1 // state와 action 객체를 참조해서 새로운 state를 반환함
   };
   default:
    return state;
 }
}

스토어

 

한 개의 프로젝트는 한 개의 스토어만 가짐

스토어 안에 현재 애플리케이션 상태와 리듀서가 들어가 있음


디스패치

dispatch

 

스토어의 내장 함수 중 하나로 액션을 발생시키는 것

 

순서

1. dispatch(action)처럼 액션 객체를 파라미터로 전달해서 호출함

2. 리듀서 함수 실행시켜서 새로운 상태 반환


구독

subscribe

 

스토어의 내장 함수 중 하나

 

용례

subscribe 함수 안에 리스너 함수를 넣어서 호출하면

액션이 디스패치 되어 상태가 업데이트될 때마다 리스너 함수가 호출됨

const listener = () => {
console.log('상태가 업데이트됨');

}
const unsubscribe = store.subscribe(listener);


unsubscribe(); // 구독을 비활성화할 때 함수를 호출

구독 비활성화할때는 unsubscribe() 함수 호출함

댓글