도리쓰에러쓰

[React] Redux3 :: state와 reducer가 더 필요하다면? 본문

코딩애플 (React)/기초수업(코딩애플) - 3

[React] Redux3 :: state와 reducer가 더 필요하다면?

강도리 2022. 1. 31. 13:02

저번 게시물에 이어서 작성하겠습니다. (코드 참고)

 

[React] Redux2 :: reducer / dispatch로 데이터 수정하기

저번 게시물에 이어서 작성하겠습니다. (코드 참고) [React] Redux1 :: props 대신 사용하기 저번 게시물에 이어서 작성하겠습니다. (코드 참고) [React] Tab 만들기와 리액트에서의 등장 애니메이션 저번

dori-coding.tistory.com


1. redux를 통해 Alert창 닫기 기능 만들기

 

1️⃣ Cart..js에 alert 창을 하나 생성합니다.

  * div class는 bootstrap에 정의되어 있는 것을 사용하였습니다.

<div className='alert alert-warning'>
    <p>지금 구매하시면 신규할인 20%</p>
    <button>닫기</button>
</div>

 

 

2️⃣ alert 창의 상태를 저장하는 state와 reducer를 만듭니다.

let alertState = true;

function reducer2(state = alertState, action) {
  return state
}

 

 

3️⃣ createStore에 reducer2()를 추가합니다.

💡 이전엔 reducer가 한개만 있었기 때문에 아래 코드와 같이 작성하였습니다.

let store = createStore(reducer);

 

하지만 reducer 여러개일 때는 combineReducers()를 사용하여 아래 코드처럼 작성하면 됩니다.

let store = createStore(combineReducers({reducer, reducer2}));

 

 

4️⃣ reducer를 합치면 store에 담긴 데이터를 사용하는 부분도 변경해야 합니다.

💡 이전에 Cart.js에서 아래와 같은 코드를 작성한 적이 있었는데, 현재 reducer가 2개이기 때문에 에러가 납니다.

function store(state){
    return {
        state : state
    }
}

 

- 실제로 console.log(state)를 찍어보면 아래 사진과 같은 결과가 출력됩니다.

 

- 에러가 나지 않으려면 아래 코드와 같이 작성하면 됩니다.

  * state에는 상품 관련한 데이터가, alertState에는 alert창의 상태에 대한 데이터가 들어있습니다.

function store(state){
    return {
        state : state.reducer,
        alertState : state.reducer2
    }
}

 

 

5️⃣ state와 reducer를 통해 alert 창이 닫히도록 해보겠습니다.

1) index.js에 있는 reducer2()를 아래 코드와 같이 변경해줍니다.

function reducer2(state = alertState, action) {
  if( action.type === 'alertClose' ) {
    state = false;
    return state;
  } else {
    return state;
  }
}

- action type이 'alertClose'일 때 state값을 false로 변경합니다.

 

2) Cart.js에 삼항연산자를 통해 alertState가 true이면 alert창이 보이고, false이면 alert창이 닫히도록 하는 기능을 작성합니다.

{
    props.alertState === true
    ? (<div className='alert alert-warning'>
            <p>지금 구매하시면 신규할인 20%</p>
            <button>닫기</button>
        </div>)
	: null
}

 

3) button onClick 이벤트리스너에 dispatch()를 작성하여 버튼을 클릭하면 데이터를 false로 데이터 수정 요청을합니다.

{
    props.alertState === true
    ? (<div className='alert alert-warning'>
            <p>지금 구매하시면 신규할인 20%</p>
            <button onClick={ () => { props.dispatch({ type : 'alertClose' }) } }>닫기</button>
        </div>)
	: null
}

 

- 아래 사진과 같이 [닫기] 버튼을 클릭하면 alert창이 닫히는 것을 확인할 수 있습니다.

 

💡 주의

저는 문법을 보여드리기 위해 state와 reducer를 Component 하나에서만 보여드렸는데,

Component 하나에서만 쓰는건 굳이 redux에 저장할 필요가 없습니다. (useState() 사용)


2. 전체 코드

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import { BrowserRouter } from 'react-router-dom';

import { Provider } from 'react-redux';
import { combineReducers, createStore } from 'redux';

let alertState = true;

function reducer2(state = alertState, action) {
  if( action.type === 'alertClose' ) {
    state = false;
    return state;
  } else {
    return state;
  }
}

let basicState = [
  { id : 0, name : 'white bag', quan : 2 }, 
  { id : 1, name : 'black bag', quan : 5 }, 
  { id : 2, name : 'red bag', quan : 0 }
];

function reducer(state = basicState, action) {
  if( action.type === '수량증가' ) {
    let copyArr = [...state];
    console.log(copyArr);
    copyArr[0].quan++;
    return copyArr;
  } else if( action.type === '수량감소' ) {
    let copyArr = [...state];
    copyArr[0].quan--;
    return copyArr;
  } else {
    return state
  } 
}

// let store = createStore(reducer);
let store = createStore(combineReducers({reducer, reducer2}));

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

Cart.js

import React from 'react';
import { Table } from 'react-bootstrap';
import { connect } from 'react-redux';

function Cart(props) {
    return(
        <div>
            <Table responsive>
                <thead>
                    <tr>
                        <th>#</th>
                        <th>상품명</th>
                        <th>수량</th>
                        <th>변경</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        props.state.map((a, i)=>{
                            return(
                                <tr key={i}>
                                    <td>{ a.id }</td>
                                    <td>{ a.name }</td>
                                    <td>{ a.quan }</td>
                                    <td>
                                        <button onClick={()=>{ props.dispatch({ type : '수량증가' }) }}>+</button>
                                        <button onClick={()=>{ props.dispatch({ type : '수량감소' }) }}>-</button>
                                    </td>
                                </tr>
                            )
                        })
                    }
                </tbody>
            </Table>

            {
                props.alertState === true
                ? (<div className='alert alert-warning'>
                        <p>지금 구매하시면 신규할인 20%</p>
                        <button onClick={ () => { props.dispatch({ type : 'alertClose' }) } }>닫기</button>
                    </div>)
                : null
            }
        </div>
    )
}

function store(state){
    return {
        state : state.reducer,
        alertState : state.reducer2
    }
}

export default connect(store)(Cart)
// export default Cart;

 

* 이외의 코드는 이전 게시물에 작성된 코드와 일치합니다.

Comments