210716 Redux(2)

다른 state 데이터도 redux로 만들고 싶다면

//Cart.js
      <div className="my-alert">
        <p>지금 구매하시면 신규할인 20%</p>
        <button>닫기</button>
      </div>

이 알림창 UI의 상태를 state로 저장해서 닫기 버튼을 누르면 사라지도록 만들자!

  • 초기 state를 만들고
  • reducer를 하나 더 만들면 됨
//index.js
let defaultalert = true;
function reducer2(state = defaultalert, action){
  return state
}

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

✨이때 combineReducers()를 써서 reducer 여러개를 한꺼번에 넘겨준다.
✨✨ reducer가 두 개 이상이면 store 데이터의 형식이 조금 달라지기 때문에 Cart.js에서 state를 props로 바꿔주는 함수(필자는 함수명을 stateToProps라고 지정함) 수정이 필요하다.

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

reducer가 여러개라면 잘 골라 써야함!!

다음으로 닫기 버튼을 누르면 알림창이 닫히게 설정한다.

//index.js
function reducer2(state = defaultalert, action){
  if (action.type==='close'){
    state = false
    return state
  }
  return state
}
//Cart.js
{
 props.alertState === true
 ?(<div className="my-alert">
 <p>지금 구매하시면 신규할인 20%</p>
 <button onClick={()=>{ props.dispatch({ type: 'close' })}}>닫기</button>
 </div>)
 :null
}


닫기 버튼을 누르면 사라짐

redux store에 온갖 데이터를 저장하는 것은 지양해야함!
알림창 UI같은 경우에는 Cart.js에서만 필요할 뿐, 다른 컴포넌트에서 필요 없음 useState를 이용하는 것이 가장 편리하고 권장되는 방법이다.

dispatch()로 수정요청시 데이터를 보내고 싶다면

dispatch({type: 요청이름, payload: 보낼 데이터})
보낸 자료는 action 파라미터에 저장된다.

  • 주문하기 버튼을 누르면 제품이 장바구니에 추가되도록하기

우선 주문하기 버튼을 눌렀을 때 함께 전송될 데이터를 만든다.

//Detail.js
<button className="btn btn-danger" onClick={() => {
   props.dispatch({type: '항목추가', payload: { id: 2, name: '새로운상품', quan: 1 }});
}}>주문하기</button>

✨이때 props.dispatch()를 그냥 쓰면 에러가 나기 때문에 꼭 밑에서 connect 해주어야 한다 (당연히 connect함수를 위에서 import 해와야 함)

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

export default connect(stateToProps)(Detail);
//export default Detail;

그리고 이 데이터를 수정하는 reducer에 가서 '항목추가' 액션에 대한 조건문을 작성해준다.

//index.js
function reducer(state = defaultState, action){
  if(action.type === '항목추가'){
    let copy = [...state];
    copy.push(action.payload); //payload에서 넘어온 것을 push해라
    return copy
  }
  else if( action.type === '증가'){ //데이터 수정 조건
    let copy = [...state];
    copy[0].quan++;
    return copy
  } 
  else if (action.type === '감소'){
    let copy = [...state];
    copy[0].quan--;
    return copy
  }
  else{
    return state
  }
  
}

그런데 Cart 페이지를 방문하면 추가한 데이터가 보이지 않음
-> 개발환경에서는 페이지를 이동하면 DB가 초기화 되기 때문이다.
-> 강제로 라우터 함수 history.push()를 이용해서 페이지를 이동시키면 데이터추가+페이지이동이 동시에 진행되면서 데이터가 초기화 되지 않음.

//Detail.js
<button className="btn btn-danger" onClick={() => {
   props.dispatch({type: '항목추가', payload: { id: 2, name: '새로운상품', quan: 1 }});
   history.push('/cart'); //강제로 페이지 이동
}}>주문하기</button>

주문하기 버튼을 누르면 페이지 내의 상품을 추가하기

props로 넘어온 데이터들을 살짝 가공해주면 된다.

<button className="btn btn-danger" onClick={() => {
 props.dispatch({type: '항목추가', payload: { id: props.shoes[id].id, name: props.shoes[id].title, quan:1 }});
 history.push('/cart'); //강제로 페이지 이동
}}>주문하기</button>

같은 상품을 계속 주문하면 항목추가 되는 것이 아니라 수량만 추가되게 하기

  1. 항목추가용으로 넘어온 데이터 중에 id값을 찾는다
  2. 현재 장바구니 품목 중에 그 id와 같은 id값을 가진 품목이 있는지 찾는다.
    ->있다면 수량만 추가하기
    ->없다면 항목을 추가하기

findIndex()
판별함수를 만족하는 첫 식별자를 반환한다.
반환타입은 Number, 값이 없다면 -1을 반환함.

function reducer(state = defaultState, action){
  if(action.type === '항목추가'){
    let copy = [...state];
    //a는 copy안의 자료 하나하나를 뜻함
    let idx = state.findIndex((a)=>{return a.id === action.payload.id});
    if(idx>=0){
      copy[idx].quan++;
    }
    else{
      copy.push(action.payload);
    }
    return copy
  }
}

강의의 예시코드랑은 조금 다른데 그냥 if else 안에 중복되던 코드를 앞 뒤로 뺐다

좋은 웹페이지 즐겨찾기