Redux

  • 상태를 업데이트 할 때는 항상 원본 state는 수정하지 않고 새로운 state를 반환해야한다.
  • 프로젝트가 더 복잡해질수록 리덕스를 올바르게 사용하기도 더 복잡해진다.
  • 리덕스에서 관리해야 할 상태가 더 많아질 때 생길 수 있는 현상
    • 액션 타입에서 문제가 생길 수 있다.
      • 식별자는 오타가 나서는 안되지만 오타가 날 경우 리듀서가 처리하지 못하게 된다.
        • 해결: 상수를 지정하여 오타를 막을 수 있다.
    • 작은 프로젝트에서는 문제가 되지않지만 큰 프로젝트에 많은 개발자가 들어가는 프로젝트에서는 문제가 될 수 있다.
      • 서로 다른 액션이 많을 때 식별자의 충돌이 발생할 수 있다.
    • 관리하는 데이터의 양이 많을 수록 상태 객체도 점점 커지며 많은 상태를 복사해야한다. 모든 상태를 유지하려면 계속 복사해야하고 리듀서의 길이가 길어지고 유지할 수 없을 만큼 리덕스의 파일이 커진다. 이것은 Context의 단점과도 같고, 리덕스에서도 나타날 수 있지만 해결책이 있다.
      • 해결: 리듀서의 파일을 나누어서 관리한다.
    • 상태의 변경 불가성에도 영향을 줄 수 있다.

Redux-toolkit

  • Redux를 더 편리하고 쉽게 사용할 수 있도록 만들어준다.
  • 위와 같은 리덕스의 단점을 해결하는 방안을 조금 더 쉽게 할 수 있고, 해결하지 못하는 단점도 보완할 수 있도록 해준다.

설치

  1. 아래의 코드를 작성하여 라이브러리를 설치한다.
  2. npm install @reduxjs/toolkit react-redux
  3. 기존에 설치한 Redux 라이브러리가 존재한다면 package.json에서 삭제해준다.
    • 이미 Redux toolkit에 포함되어 있기 때문이다.

사용

reducer 설정

  • slice는 항상 이름이 존재해야 한다.
// store -> index.js
import { createSlice } from '@reduxjs/toolkit';

const initialState = { counter: 0, showCounter: true };

const counterSlice = createSlice({
	// 식별자
	name: 'counter',
	initialState,
	reducers:{
		// 자동으로 최신 state를 받는다.
		increment(state) {
			// 기존의 상태를 변경하는 것 같지만 변경되지 않는다.
			// 내부적으로 immer라는 다른 패키지를 사용한다.
			// 이런 코드를 감지하고 자동으로 원래 있느 상태를 복제하고 기존 상태를 변경하지 않도록해준다.
			// 불변성을 신경쓰지 않아도 된다.
			state.counter++;
		},
		decrement(state) {
			state.counter--;
		},
		// action에 붙어있는 데이터가 필요할 때 사용하는 방법.
		increase(state, action) {
			state.counter = state.counter + action.amount;	
		},
		toggleCounter(state) {
			state.showCounter = !state.ShowCounter;
		}
	}
});

// counterSlice.reducer에 접근 가능하다.
// 프로젝트 규모가 커졌을 경우 문제가 생길 수 있다.
// ㄴ 일반적인 redux에서는 combineReducers를 사용한다.
//    ㄴ redux-toolkit에서는 configureStore를 사용한다.
// configureStore는 createStore처럼 store를 생성한다.
// 여러 개의 리듀서를 하나의 리듀서로 쉽게 합칠 수 있다.
// redux
const store = createStore(counterSlice.reducer);

// redux-toolkit
const store = configureStore({
	// reducer가 하나 일 경우
	reducer: counterSlice.reducer
	// reducer가 여러개 일 경우
	reducer: { counter: counterSlice.reducer }
});

Reducer 사용, state 가져오기

export const counterActions = counterSlice.actions;

// reudcer 사용하기
// payload가 없는 경우
dispatch(counterActions.increment());

// payload가 있는 경우
dispatch(counterActions.increase(10));

'Coding > React & React-native' 카테고리의 다른 글

[RN] React Native란?  (0) 2023.12.22
[React] React Hook Form과 yup을 사용한 유효성 검사  (0) 2022.11.21
[React] Vite를 사용해보자  (0) 2022.10.25
[Redux]React-redux 사용하기  (0) 2022.10.25
[React] Portals  (0) 2022.07.16

Vite란?

공식문서에 따르면 프랑스어로 빠르다를 의미하고, 빠르고 간결한 모던 웹 프로젝트 개발 경험에 초점을 맞춰 탄생한 빌드 도구이다.

  • 개발 시 네이티브 ES Module을 넘어 더욱 다양한 기능을 제공한다.
  • 번들링 시, Rollup 기반의 다양한 빌드 커맨드를 사용할 수 있습니다. 이는 높은 수준으로 최적화된 정적(static) 리소스들을 배포할 수 있게끔 하며, 미리 정의된 설정(Pre-configured)을 제공합니다.

Create React App대신 사용하는 이유

CRA는 JavaScript로 구성된 Webpack을 사용하는데 속도가 느린편입니다. 평소에는 못느낄 수 있지만 처리해야 할 코드의 양이 많아질 수록 느린 속도를 채감할 수 있습니다.
위와 같은 단점을 해결하기 위해 Esbuild를 기반으로 만들어진 빌드툴인 Vite를 사용하게 됩니다.

*Esbuild: Go 언어로 작성된 JavaScript 빌드툴로 속도가 빠르다.

지원중인 템플릿

  • vanilla
  • vue
  • react
  • preact
  • lit
  • svelte

Vite 설치하기

아래와 같은 명령어를 입력하여 설치할 수 있습니다.
Vite를 사용하기 위해서는 14.18+, 16+의 Node.js를 요구하며 템플릿에 따라 더 높은 버전의 Node.js를 요구할 수 있습니다.

npm create vite@latest

yarn create vite

템플릿 생성하기

React로 작성을 할 것이기 때문에 템플릿 명으로 react를 작성하면 됩니다.
TypeScript의 경우 템플릿-ts를 붙여작성하게 됩니다.

# npm 6.x
npm create vite@latest ${디렉터리 명} --template ${템플릿 명}

# npm 7+
npm create vite@latest ${디렉터리 명} -- --template ${템플릿 명}

# JavaScript react 템플릿 생성
npm create vite@latest vite-test -- --template react

# TypeScript react-ts 템플릿 생성
npm create vite@latest vite-test -- --template react-ts

Vite 실행

npm run dev

참고자료

'Coding > React & React-native' 카테고리의 다른 글

[React] React Hook Form과 yup을 사용한 유효성 검사  (0) 2022.11.21
[Redux] Redux-toolkit  (0) 2022.11.21
[Redux]React-redux 사용하기  (0) 2022.10.25
[React] Portals  (0) 2022.07.16
[React] Fragment  (0) 2022.07.12

Redux?

상태를 전역적으로 관리하기 위해서 사용되는 상태관리 도구이며, Redux 외에도 MobX, React Context, Recoil 등이 있습니다.
상태관리 도구를 사용하여 Props drilling 이슈를 해결할 수 있습니다.

Props drilling?
상태가 존재하는 컴포넌트에서 자식 컴포넌트로 이동을 할 때, 수많은 props를 계속해서 내려야하는 경우를 말하며, 코드의 가독성이 나빠지고 유지보수 또한 힘들어집니다.

Action

상태에 어떤 Action(행동)을 취할 것인지 정해놓는 객체입니다.
Action이 많아질 경우 ActionTypes 파일을 생성하여 타입을 모아두는 경우도 있습니다.
Action 타입을 정의할 때는 모두 대문자로 Snake Case로 작성합니다.

// 전달 받을 값(payload)가 없을 경우
export const loginSuccess = () => ({
  type: "LOGIN_SUCCESS"
})

// 전달 받을 값(payload)가 있을 경우
// payload는 주로 단일 데이터, 객체로 받습니다.
export const loginInfo = (res) => ({
  type: "LOGIN_INFO",
  payload: res
})

Reducer

Dispatch에서 전달받은 Action(행동) 객체의 type에 따라서 상태를 변경시키는 함수입니다. Reducer가 여러개 일 경우 combineReducers를 사용하여 하나로 묶어줄 수 있습니다.

Store

상태가 관리되는 오직 하나뿐인 상태 저장소의 역할을 합니다.
createStore을 사용할 경우 toolkit을 사용하라는 의미로 밑줄이 그어집니다.

import { createStore } from "redux";
import rootReducer from "./redux/reducers";

// Reducer를 연결한다.
const store = createStore(rootReducer);

export default store;

React-redux 초기 세팅

redux 라이브러리 설치

React에서 Redux를 사용하기 위해서는 redux, react-redux를 모두 설치해야 합니다.
아래의 코드에서 @reduxjs/toolkit은 후에 react-toolkit을 사용하기 위해 설치한 것입니다.

npm install @reduxjs/toolkit redux react-redux

파일 구조 생성

redux-test
└─ src
   ├─ App.js     메인화면
   ├─ Compo1.js  프롭받을 컴포넌트
   ├─ Compo2.js  프롭받을 컴포넌트
   ├─ index.css
   ├─ index.js
   ├─ redux
   │  ├─ actions  액션 정의
   │  │  └─ login.js
   │  └─ reducers 상태 변경 함수
   │     ├─ index.js
   │     └─ loginReducer.js
   └─ store.js    상태 저장소

Actions 폴더 생성

  • 액션에 관한 파일 생성
  • 액션 타입과 액션을 각각의 파일로 생성해도 무관하다.
// login.js
export const LOGIN_SUCCESS = "LOGIN_SUCCESS";
export const LOGIN_INFO =  "LOGIN_INFO";

export const loginSuccess = () => ({
  type: LOGIN_SUCCESS
})

export const loginInfo = (res) => ({
  type: LOGIN_INFO,
  payload: res
})

Reducers 폴더 생성

  • 리듀서를 정의할 파일 생성
// index.js
import { combineReducers } from "redux";
import loginReducer from "./loginReducer";

// 여러 리듀서들을 하나로 묶어준다.
const rootReducer = combineReducers({
  loginReducer,
});

export default rootReducer;

// loginReducer.js
import { LOGIN_SUCCESS, LOGIN_INFO } from "../actions/login";

// 초기 상태 지정
const initialstate = {
  isLogin: false,
  userName: "",
};

// 초기 상태 불변성
const loginReducer = (state = initialstate, action) => {
  switch (action.type) {
    case LOGIN_SUCCESS:
      return {
        // 순서 중요
        ...state,
        isLogin: true,
      };
    case LOGIN_INFO:
      return {
        isLogin: true,
        userName: action.payload,
      };
    default:
      return state;
  }
};

export default loginReducer

루트 폴더 src폴더에 store.js 파일 생성

  • store.js: 상태가 저장되는 저장소
// store.js
// 취소선: redux toolkit 사용하란 의미
import { createStore } from "redux";
import rootReducer from "./redux/reducers";

const store = createStore(rootReducer);

export default store;

Redux 상태 사용하기

Redux의 상태를 변경 및 불러오기 위해서는 useDispatch, useSelector가 필요합니다.

useDispatch

Reducer를 호출하여 Action을 전달해주는 함수이다. 전달인자로는 Action의 객체가 전달된다.
useDispatch를 사용하기 위해서는 변수에 할당해 준뒤 사용할 수 있다.

import { useDispatch } from "react-redux";
import { loginInfo, loginSuccess } from "./redux/actions/login";

// 사용하기위해 변수에 할당(함수형식)
const dispatch = useDispatch();

// 전달인자가 없을 경우
dispatch(loginSuccess());

// 전달인자가 있을 경우
dispatch(loginInfo("homil2"));

useSelector

컴포넌트와 state를 연결하여 Redux의 state에 접근할 수 있게 해주는 메서드이다.
함수내에서는 사용할 수 없다.

import { useSelector } from "react-redux";

// 위에서 정의한 loginReducer의 상태 값을 객체로 받아온다.
useSelector((state) => state.loginReducer)

실사용

로그인 버튼 클릭시 로그인상태가 유지되며 유저네임을 작성후 전송하면 해당 유저의 이름이 같이 담기도록 하는 코드를 구현했다.

// app.js
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { loginInfo, loginSuccess } from "./redux/actions/login";

const App = () => {
  const dispatch = useDispatch();
  const [name, setName] = useState("");

  const nameChange = (el) => {
    setName(el)
  };
  console.log(useSelector((state) => state.loginReducer))

  const loginBtnClick = () => {
    dispatch(loginSuccess())
    dispatch(loginInfo(name))
  };

  return (
    <div className="container">
      <div>
        <label htmlFor="name">이름</label>
        <input id="name" onChange={(el) => nameChange(el.target.value)}></input>
      </div>
      <div>
        <button type="button" onClick={loginBtnClick}>
          로그인
        </button>
      </div>
    </div>
  );
};

export default App;

// index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

'Coding > React & React-native' 카테고리의 다른 글

[Redux] Redux-toolkit  (0) 2022.11.21
[React] Vite를 사용해보자  (0) 2022.10.25
[React] Portals  (0) 2022.07.16
[React] Fragment  (0) 2022.07.12
[React] React 디버깅  (0) 2022.07.08

React 프로젝트 구성 #1 (프로젝트 생성)

Firebase를 사용하여 React 프로젝트에서 Firestore를 사용할 수 있도록 작업을 시작해보겠습니다.

1. Firebase 로그인 및 콘솔로 이동

구글 계정을 생성후 firebase.google.com 링크에 접속하여 우측 상단에 있는 '콘솔로 이동'을 클릭하여 Firebase 프로젝트를 생성하러 이동합니다.

2. 프로젝트 생성

콘솔로 이동하게 되면 중앙에 프로젝트 추가 버튼을 클릭해줍니다.

 

프로젝트의 이름을 지정합니다.

애널리틱스를 설정합니다.

*애널리틱스: 무제한 무료 분석 솔루션인 Google 애널리틱스를 사용하면 Firebase Crashlytics, 클라우드 메시징, 인앱 메시지, 원격 구성, A/B 테스팅, Cloud Functions에서 타겟팅, 보고 등을 이용할 수 있습니다.

애널리틱스 계정을 Default로 설정하고 프로젝트 만들기를 클릭합니다.

3. 웹 앱에 firebase 추가하기

위의 과정을 진행하셨다면 해당 프로젝트 페이지로 이동이됩니다.

이동 후 가운데 IOS, Android, web 중 시작하려는 프로젝트의 유형을 지정할 수 있습니다.

저는 React로 웹 프로젝트를 작성할 것이기 때문에 웹 </>을 클릭하여 주겠습니다.

클릭을 하게 되면 아래와 같은 화면이 나오게 되면 생성하게 될 앱의 이름을 등록하여 프로젝트에서 사용할 수 있는 API키를 생성하여 줍니다.

앱 등록을 정상적으로 클릭하셨다면 Firebase SDK를 설치하는 코드와 API Key가 생성되게 됩니다.

이번글에서는  Firebase의 가장 기초적인 프로젝트 생성까지 진행을 했습니다.

다음 글에서는 React에 firebase 모듈을 설치하여 SDK(API Key)를 지정하는 방법까지 진행하겠습니다.

'Coding > Firebase' 카테고리의 다른 글

[Firebase] Firebase?  (0) 2022.07.24

Firebase?

모바일 및 웹 애플리케이션을 만들기 위해 개발된 플랫폼입니다.

Firebase로 플랫폼을 구축 시 자동적으로 서버를 구축해주어 리눅스의 명령어를 알 필요가 없으며, 인증, 데이터베이스, 스토리지, API 등을 구성하는데 조금 더 간편하게 작업을 할 수 있도록 도와줍니다. 이를 통해서 적은 비용으로 좋은 앱을 만들 수 잇습니다.

기능

기본적으로 가장 많이 사용하는 기능만 적어보도록 하겠습니디ㅏ.

Authentication

  • 계정 기능을 쉽게 만들 수 있게 해주는 API입니다.
  • SNS 로그인 기능 또한 구현할 수 있습니다.

Cloud Firestore

  • SQL 언어를 사용하지 않고, 클라우드에 데이터를 저장하여 사용할 수 있습니다.

실시간 데이터베이스

  • 사용자 기반 보안으로 온/오프라인에서 실시간에 가깝게 JSON 데이터를 저장하고 사용자간에 동기화하여 서버리스 앱을 빌드합니다.

Cloud Messaging

  • 플랫폼 전체에서 무료로 서버와 기기 간에 푸스 메시지를 안정적으로 주고 받을 수 있게해줍니다.

Hosting

  • 웹 사이트를 간편하게 배포하게 해줍니다.

Cloud Storage

  • 사용자의 콘텐츠(사진, 동영상 등)을 저장하여 사용할 수 있습니다.

참고자료
Firebase 공식문서

'Coding > Firebase' 카테고리의 다른 글

[Firebase] React 프로젝트 구성 #1  (0) 2022.07.24

Portals

Fragment를 사용하면 깔끔한 코드를 작성할 수 있습니다.

React Portals은Fragment와 비슷한 일을 하여 간결한 코드를 작성하는데 사용됩니다.

부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링 하는 최고의 방법입니다.

ReactDOM.createPortal(child, container)

첫 번째 인자 child는 엘리먼트, 문자열, fragment와 같은 어떤 종류이든 렌더링할 수 있는 React자식 요소입니다.

두 번째 인자 container는 DOM 엘리먼트입니다.

사용법

일반적인 컴포넌트 렌더링 메서드에서 요소를 반환할 때, 해당요소는 부모 노드에서 가장 가까운 자식으로 연결됩니다.

portal의 전형적인 동작 방법은 부모 컴포넌트에 overflow: hidden이나 z-index가 있는 경우 이지만, 시각적으로 자식을 보여줘야 하는 경우가 있습니다. (다이얼로그, 호버카드, 툴팁, 모달 등)

// 일반적인 렌더링 방법
render(){
	return (
    	<div>
        	{this.props.children}
        </div>
    );
}

// Portal을 이용한 렌더링 방법
render(){
	return ReactDOM.createPortal(
    	this.props.children,
        domNode
    );
}

참고자료

https://ko.reactjs.org/docs/portals.html

 

Portals – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

'Coding > React & React-native' 카테고리의 다른 글

[React] Vite를 사용해보자  (0) 2022.10.25
[Redux]React-redux 사용하기  (0) 2022.10.25
[React] Fragment  (0) 2022.07.12
[React] React 디버깅  (0) 2022.07.08
[Redux] Redux?  (0) 2022.07.01

+ Recent posts