[shop-project] reducer / dispatch

kirin.log·2021년 4월 30일
1

🌈 reducer

  • 리액트(react) 상태(State) 생성자(Producer) = re ducer
  • 액션(Action)이 전달되면, 리듀서(Reducer)가 스토어(Store)의 상태(State)를 변경한다. 즉, state변경함수와 같은 의미의 역할을 한다.
  • reducer는 state데이터의 수정 방법을 미리 정의 해놓는 역할을 한다.
  • reducer는 두 가지의 파라미터를 받는다 ➡ state초기값(변수로 미리 담아놓음), action(state를 변화할 액션에 활용)

🍎 reduce 사용 방법

1) store에 담은 state초기값을 변수로 빼주고, createStore의 인자에 reducer를 넣는다
let store = createStore(reducer) ➡ state초기값을 담는 공간에 reducer 넣기

2) state 데이터를 변수에 담기
const initState = "state초기값 담아주기" ;

3) reducer 함수 생성 ➡ 인자 2개 받는다( 1.state초기값 지정, 2.action)

 function reducer(state=initState, action) {
     // state 데이터의 수정 조건을 if문으로 걸어주고, 수정된 state를 리턴한다
     if( 액션.type === 수정방법이름 ) {   
         변경 과정 (1.state deepcopy ➡ 2.state변경)
         return 수정된state 
     }
     // else로 항상 state값을 return 한다(무조건!!!!!) ➡ 변경되지 않으면 기본 state를 출력해야함
     else { 
         return state 
     }
 };

4) state데이터를 가져올 컴포넌트에서 state변경을 해준다
props.dispatch( {액션(객체형태)} 을 인수로 받는다 )

❗ 순서:
(1) 기본 state데이터 변수에 담기(initState)
(2) reducer함수 생성하기(안에 조건문을 통해 변경조건과 기본 state return 해주기)
(3) let store = createStore(reducer)해주기 (🪓reducer 함수 밑에 써주기)


🌈 dispatch

  • dispatch는 스토어(store)의 내장함수 중 하나이다. 액션(action)을 발생 시키는 역할을 한다.
  • state상태에 어떤 변화를 일으켜야 할 때는 액션(Action) 이라는 것을 스토어(store)에 전달한다. 액션은 객체 형태로 되어 있으며, state상태를 변화시킬 때 이 객체를 참조하여 변화를 일으킨다. 액션을 store에 전달하는 과정을 디스패치(dispatch)라고 한다.
    데이터 수정 요청을 할 때는, props.dispatch( {action객체} )

🐻 reducer & dispatch 적용 예시

// index.js

// redux
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';

// (1) state초기값을 변수에 담아준다(여러개면 배열형식)
let initState =  [  // state초기값을 객체로 여러개(배열)담음.
    	           {id: 0, name: 멋진신발, quan: 2},
                   {id: 1, name: 예쁜신발, quan: 3},
                   {id: 3, name: 귀여운신발, quan: 1}
                 ] 
// (2) reducer 함수를 생성한 뒤, state초기값과 action을 인자에 담는다            
function reducer(state=initState, action) {
  // state변경 조건 정의
  if( action.type === '수량증가') {
    // state변경 내용 정의
    let copy = [...state];  // deepcopy
    copy[0].quan++;         // 변경 내용  
    return copy             // 수정된state 리턴
  }
  else if {
    // default로 기본state 리턴하도록 정의
    return state
  }
}

// (3) store를 생성 후, store에 reducer를 담는다
const store = createStore(reducer)    

ReactDOM.render(
  <BrowserRouter>
    <Provider store={store}>  // state초기값을 담은 store변수를 provider에 담는다
      <App />
    </Provider>
  </BrowserRouter>, document.getElementById('root')
);





// Cart.js
import React from 'react';
import { connect } from 'react-redux';  // import 해주기

const Cart = (props) => {
  return (
    <div className="Cart">
       // 코드 생략
       {
         props.state.map( (a, i) => {
          return (
           <tr key={i}>
            <td>{i+1}</td>
            <td> { props.state[i].name } </td>
            <td> { props.state[i].quan } </td>

             // 버튼을 누르면 state의 수량(quan)이 증감함
            <button onClick={ () => { props.dispatch( {type: '수량증가'} )}}> + </button>
                                           // dispatch 인수에서 Ruduce로 넘길 객체 = action
                                           // dispatch내 action은 객체 형태이다 
           </tr>
          )
         })
       }
    </div>
  );
};


function cartInfo(state) {
    return {
        // state데이터를 state라는 이름의 props로 등록하는 것.
        state: state
    }
};

export default connect(cartInfo) (Cart)

🐹 state와 reducer가 여러개일때 어떻게 적용할까?

  • 복수의 reducer를 createStore에 담기 위해 combineReducers를 사용한다
    ❗ combineReducer = reducer를 합치는 기능
// index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// redux
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { combineReducers, createStore } from 'redux';  // combineReducers import하기

// 첫 번째 state & reducer
let initState =  [ 
    	           {id: 0, name: 멋진신발, quan: 2},
                   {id: 1, name: 예쁜신발, quan: 3},
                 ] 
         
function reducer(state=initState, action) {
  if( action.type === '수량증가') {
    let copy = [...state];  // deepcopy
    copy[0].quan++;         // 변경 내용  
    return copy             // 수정된state 리턴
  }
  else {
    return state
  }
}

// 두 번째 state & reducer
function reducer2(state=true, action) {
  if(action.type === 'close') {
    state = false;
    return state 
  }
  else {
    return state
  }
}


                           // 두 개의 reducer를 합쳐준다(combineReducers)
const store = createStore( combineReducers({reducer, reducer2}) )   
❗ combineReducer를 사용할 때는 
(1) import 해온다 
(2) store인자 안에 묶어준다(인자로 reducer들을 복수로 받는다. 중괄호 감싸주기)

ReactDOM.render(
  <BrowserRouter>
    <Provider store={store}>  // state초기값을 담은 store변수를 provider에 담는다
      <App />
    </Provider>
  </BrowserRouter>, document.getElementById('root')
);





// Cart.js
import React from 'react';
import { connect } from 'react-redux';  // import 해주기

const Cart = (props) => {
   return (
     <div className="Cart">
        // 코드 생략
        {
          props.state.map( (a, i) => {
           return (
            <tr key={i}>
             <td>{i+1}</td>
             <td> { props.state[i].name } </td>
             <td> { props.state[i].quan } </td>

              // 버튼을 누르면 state의 수량(quan)이 증감함
             <button onClick={ () => { props.dispatch( {type: '수량증가'} )}}> + </button>
                                           // dispatch 인수에서 Ruduce로 넘길 객체 = action
                                           // dispatch내 action은 객체 형태이다 
            </tr>

             // reducer2로 받아온 state데이터를 활용한 조건문
            {
              props.alertState === true   // 하단에 props화 해놓음
              ? ( <div className="alert">
                    <p>지금 구매하시면 신규할인 20%</p>
                    <button onClick={() => {props.dispatch( {type: 'close'} )}}>닫기</button>
                    // state데이터를 수정요청하는 dispatch 지정(state변경)
                  </div> )
              : null
            }
          )
         })
       }
    </div>
  );
};


// reducer를 2개 받는다. 인자로 받은 state에는 2개의 reducer가 들어있다
function cartInfo(state) {
    return {
        state: state.reducer  // 첫 번째 reducer의 state데이터를 props 로 등록
        alertState: state.reducer2   // 두 번째 reducer의 state데이터를 props로 등록     
    }
};

export default connect(cartInfo) (Cart)
profile
boma91@gmail.com

0개의 댓글