생활코딩 React-Redux

Jake·2022년 7월 6일
2

React x Redux

목록 보기
1/1

React

사용자 정의 태그, 즉 Component 를 만들어서 체계적이고 잘 정돈된 앱을 만들게 해주는 기술

  • context API 활용 (비교적 작은 스케일의 프로젝트에서 사용)

Redux

State를 중앙에서 관리해서 데이터가 예기치 않게 변경되는 가능성을 낮춰주는 기술임. (비교적 큰 스케일의 프로젝트에서 상태관리를 위해 사용)

공통점: 모두 개발의 복잡성을 낮춰주는 기술로써, 함께 활용시 시너지효과를 얻을 수 있다.



Redux 개념요약

  • WITHOUT REDUX

    props 방식으로 컴포넌트간 데이터를 교환, depth가 깊어질 수록
    코드가 복잡하고 길어지게 된다.
  • WITH REDUX

    단일 store에 state를 저장하는 방식으로 컴포넌트가 직접 store로부터
    state를 전달받을 수 있다.

REDUX 여행의 지도(메커니즘)

    store 내부요소

  • Action: {type: 'ACTION_NAME', payload: 1000}

    Object 형태로 dispatch() 인자로 전달한다.

  • Reducer: (state,action)을 인자로 받아 새로운 state를 반환

    초기 1회 따로 명시하지 않는다면 (state === undefined) 로 호출된다.

  • State: reducer에 의해 반환되는 상태값

    store.getState()형태로 참조된다.

  • store 내장메서드( store.Method() )

    -Dispatch(): action객체를 받아 reducer에 전달하며 reducer를 호출한다.
    (이후 reducer를 호출하고 state 변경이 완료되면 subscribe()를 호출한다.)

    -Subscribe(): 등록된 함수,컴포넌트들을 다시 호출(렌더링)

    -getState(): store.getState() 형태로 state값을 참조할 수 있다.

    Redux 동작 메커니즘

  • [UI]
    사용자가 특정 기능을 동작시킨다
  • [EventHandler]
    이벤트핸들러로 dispatch()에 action이 담긴 형태로 호출
    action: { type: 'DEPOSIT', payload: 10 }
  • [dispatch]
    전달받은 action을 state와 함께 reducer에 다시 전달하며 호출
  • [state]
    reducer( initialState, action) 가 동작하여 특정 state를 반환
    새로 변경된 state는 store를 통해서만 참조할 수 있다.

React-Redux

설치

npm install @reduxjs/toolkit

>store.js

'src/store.js'
//store.js에서 store를 생성(반드시 reducer도 함께 정의해야함)
import {createStore} from 'redux';
export default createStore(function reducer(state,action){
    if(state === undefined){
        return {number:0}
    }
    if(action.type === 'INCREMENT'){
        return {...state, number:state.number + action.size}
    }
    return state;
},window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);


Presentational & Container 컴포넌트 방식 (deprecated )

  • Presentational: 보여지는 UI만을 담당할 컴포넌트

  • Container Component: 리덕스의 store와 관련 처리를 맡을 래핑 컴포넌트

[컴포넌트 래핑의 목적]

프레젠테이셔널 컴포넌트가 여전히 부품으로써의 역할을 할 수 있도록
(다른 프로젝트에서도 코드를 재사용가능 하도록)
리덕스코드를 분리시키는 과정

[컴포넌트를 래핑하는 방법]

  1. Presentational Component를 감싸는 컨테이너 컴포넌트(리덕스,스토어와 관련 처리를 맡는)를 만든다.
  2. 부모 컴포넌트Container Component를 임포트해서 렌더링한다.
  3. Container Component는 다시 Presentational Component를 임포트해서 렌더링하고, 리덕스 관련 처리를 맡는다.
  4. Presentaional Component는 UI를 담당하는 원본 컴포넌트.

[구조]

<App>
  <AddNumberRoot>
	<Anonymus>  ('컨테이너컴포넌트', 리덕스 관련 작업을 이 컴포넌트가 처리) 
	  <AddNumber/> (화면에 무언가 표시하는 데에 집중하는 'Presentaitonal Component' 가 됨) 
    <Anonymus/>
  <AddNumberRoot/>
<App/>

connect()() API & Provider 컴포넌트

react-redux 라이브러리에서 제공하는 API & 컴포넌트

  • connect(mapStateToProps,mapDispatchToProps)(Wrapped Component)
    // redux의 state,dispatch를 Wrapped Component에 props로 전달
  • {Provider}
    // App을 래핑하는 컴포넌트로 store를 전역에 제공, 전역 store.참조
'src/index.js'

import {Provider} from 'react-redux'; 
//(리액트 리덕스 제공 컴포넌트이다=> App을 감싸줌)
import store from './store';
//store.js파일 임포트

ReactDOM.render(
 <Provider store={store}> // store라는 props를 <Provider>에 제공하며 <App>을 감싸준다.
	<App />
 </Provider>
, document.getElementById('root'));
//이로써 App의 모든 하위 컴포넌트에 store를 전역으로 사용할 수 있다.
//=> 각 컴포넌트에 import store from "../store";를 해줄 필요가 없다.

Connect()함수는 두 인자를 받는다.

Connect(mstp,mrtp)는 (Wrapped_Component)를 인자로 받는 함수를 리턴하고,
이 함수는 다시 Wrapped_Component를 래핑한 컨테이너컴포넌트를 리턴한다.

  • mapStateToProps(state === store.getState())

function mapReduxStateToReactProps(state){
 return {
  number:state.number.     //위 함수는 객체를 리턴, number는 props_name
   /* ~ <DisplayNumber number={this.state.number}/>
   (presentational) */
}
/*Redux state를 React의 props로 mapping-연결 해주는 함수
Redux.store의 state값이 인자로 기본적으로 제공되고, 
store의 state값이 변경될 때마다
mapReduxStateToProps가 호출되고, 이는 DisplayNumber(pr)에 number라는 props이름으로
{state.number}가 제공된다.
*/, 
store.subscribe(function(){
 this.setState({number:store.getState().number);}.bind(this));
//코드와
render(){
  return <DisplayNumber number={this.state.number}></DisplayNumber>
/*의 number props를 React의 Presentational 컴포넌트에 전달하는 코드를 합친 것이 위 메서드의 특징이다.
[Redux.store.state 바뀔 때마다 return을 해주는데? 리턴해주는 객체는 React(wrapping)컴포넌트의 Props로 전달된다.]*/
  • mapDispatchToProps(dispatch === store.dispatch)
function mapDispatchToProps(dispatch){
  // === function mapReduxDispatchToReactProps(dispatch) 
 return {
 onClick: function(size){
    dispatch({type: 'INCREMENT', size:size});
   }
//dispatch(actio)이 담긴 이벤트핸들러를 객체에 메서드형식으로 리턴
}
export default connect(null, mapDispatchToProps)(AddNumber);
//Redux Dispatch를 React의 props로 mapping-연결 해주는 함

  
//cf.) 원래 방식대로의 코드
import AddNumber from '../components/AddNumber';
import React, { Component } from 'react';
import store from '../store';

export default class extends Component{
    render(){
        return <AddNumber onClick={function(size){
            store.dispatch({type: 'INCREMENT', size: this.state.size});
        }.bind(this)}></AddNumber>
    }
}

공통점: 두 메서드 모두 객체를 return하며 프로퍼티네임이 Props_name이다.
사용이유 : <Container>에서 <Presentational>에 쉽게 props전달이 가능하다.


생각해볼 점

Q .하지만 위와같은 구조는 왜 사양된다, WHY? [추가 예정]

React Hooks의 등장으로 동일한 기능을 Hook으로 대체할 수 있고
CustomHook을 사용하는 것이 더욱 직관적이기 때문이다.

Reference

[1] 생활코딩 react-redux
[2] https://velog.io/@velopert/using-redux-in-2021
[3] https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

profile
young하고 MZ해요

0개의 댓글