관리 메뉴

CASSIE'S BLOG

[슈퍼코딩] 72강 리덕스 본문

PROGRAMMING/슈퍼코딩 강의 정리

[슈퍼코딩] 72강 리덕스

ITSCASSIE1107 2023. 11. 17. 20:39
반응형

조금 복잡한 로직을 해볼거라고 함

Action에 payload 전달하기
여러 개의 state 속성 전달하기

Action에 payload 를 통해 값을 전달하면
더 다양하고 복잡한 로직을 처리할 수 있게 된다.

Input을 통해 사용자로부터 값을 입력 받아 action를 처리해 줄 수도 있다.

Store에서 여러 개의 데이터를 object 형태로 다룰 수 있다.

여러 개의 state의 속성을 다룰 때는 주의할 점이 있다.

항상 Reducer은 state를 덮어쓴다는 점이다.

만약 어떤 속성을 값을 입력하게 되지않으면, 그 값을 reducer는 undefined 처리하게 된다.

71강 실습 끝난거에서 시작함. 

import { useSelector, useDispatch } from 'react-redux';
import classes from './Counter.module.css';

const Counter = () => {
  const toggleCounterHandler = () => {};
  const counter = useSelector((state)=>state.counter);
  const dispatch = useDispatch();


  const incrementHandler = () => {
    dispatch({type: "increment"});
  }

  const decrementHandler = () => {
    dispatch({type: "decrement"});
  }

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      <div className={classes.value}>{counter}</div>
      <button onClick={toggleCounterHandler}>토글 카운터</button>
      <button onClick={incrementHandler}>증감 카운터</button>
      <button onClick={decrementHandler}>감소 카운터</button>
    </main>
  );
};

export default Counter;

 

✅dispatch를 할 때 증가할 만큼의 숫자를 같이 담아서 그 숫자를 추가해주는 로직을 해볼거라고함.

mount 그걸 주고, 

action.amount로 받아오기만 하면 되는거임.


리덕스의 리듀서는 state 값을 바꿀 때마다 새로운 state를 덮어쓰기 때문에 ..
실습 꼭 하기

안 덮어쓰게 하려면 …을 써야한다 (? 맞나?)

…state 이렇게 써주면
바뀐 state는 바뀐 state로 적용하고
안 바뀐 state는 안 바뀐 state로 그냥 간다.

 

✅ 내 코드 적용이 안됐었다..그래서 3번쨰 if문이 죽어있었던거임. 

 

import {createStore} from 'redux'

const counterReducer = (state = {counter : 0}, action) => {
    if(action.type === 'increment'){
        return {
            counter: state.counter + 1
        }
    }

    if(action.type === 'decrement'){
        return {
            counter: state.counter - 1
        }
    }
    return state;


    if(action.type === 'increase'){
        return {
            counter: state.counter + action.amount
        }
    }
    return state;


   
}

const store = createStore(counterReducer);

export default store;

 

그러면 counter가 10씩 잘 증가함. 

 

 

 

이 숫자가 보여지는지 show and hide flag를 만들기

 

state에서 추가할 예정

 

if 문 toggle 추가

 

import {createStore} from 'redux'

const counterReducer = (state = {counter : 0, showCounter: true}, action) => {
    if(action.type === 'increment'){
        return {
            counter: state.counter + 1
        }
    }

    if(action.type === 'decrement'){
        return {
            counter: state.counter - 1
        }
    }



    if(action.type === 'increase'){
        return {
            counter: state.counter + action.amount
        }
    }

    if(action.type === 'toggle'){
        return {
            showCounter: !state.showCounter,
        }
    }
    return state;


   
}

const store = createStore(counterReducer);

export default store;

 

 

toggleCounter

 

import { useSelector, useDispatch } from 'react-redux';
import classes from './Counter.module.css';

const Counter = () => {
  const toggleCounterHandler = () => {
    dispatch({type: "toggle"})
  };
  const counter = useSelector((state)=>state.counter);
  const dispatch = useDispatch();


  const incrementHandler = () => {
    dispatch({type: "increment"});
  }

  const decrementHandler = () => {
    dispatch({type: "decrement"});
  }

  const increase10Handler = () => {
    dispatch({type: "increase", amount: 10});
  }

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      <div className={classes.value}>{counter}</div>
      <button onClick={toggleCounterHandler}>토글 카운터</button>
      <button onClick={incrementHandler}>증감 카운터</button>
      <button onClick={increase10Handler}>숫자 10 증가 카운터</button>
      <button onClick={decrementHandler}>감소 카운터</button>
    </main>
  );
};

export default Counter;

 

여기서 끝이 아니라... 

 

✅ 이 로직을 컴포넌트에도 적용을 해줘야지 바뀌는 변화들을 볼 수 있다. 

 

Counter.js에서 showCounter라는 속성을 받아와야하는데
useSelctor를 이용해서 counter를 받아왔던 것처럼
showCounter도 마찬가지로 useSelector에서도 state에서 state.showCounter를 받아오도록 하겠습니다.

 

✅showCounter가 true면 보여주고 true 아니면 안 보여주고
showCounter && 
이런 식으로 표현하면 됨

 

import { useSelector, useDispatch } from 'react-redux';
import classes from './Counter.module.css';

const Counter = () => {
  const toggleCounterHandler = () => {
    dispatch({type: "toggle"})
  };
  const counter = useSelector((state)=>state.counter);
  const showCounter = useSelector((state)=>state.showCounter);
  const dispatch = useDispatch();


  const incrementHandler = () => {
    dispatch({type: "increment"});
  }

  const decrementHandler = () => {
    dispatch({type: "decrement"});
  }

  const increase10Handler = () => {
    dispatch({type: "increase", amount: 10});
  }

  return (
    <main className={classes.counter}>
      <h1>Redux Counter</h1>
      {showCounter && <div className={classes.value}>{counter}</div>}
      <button onClick={toggleCounterHandler}>토글 카운터</button>
      <button onClick={incrementHandler}>증감 카운터</button>
      <button onClick={increase10Handler}>숫자 10 증가 카운터</button>
      <button onClick={decrementHandler}>감소 카운터</button>
    </main>
  );
};

export default Counter;

 

✅자바스크립트의 논리연산자 &&

 

JavaScript의 논리 연산자인 "AND" (&&)를 사용하여 조건을 간결하게 표현한 부분입니다.

JavaScript에서 && 연산자는 두 개의 피연산자가 모두 true일 때만 true를 반환하고, 그렇지 않으면 첫 번째 false 값을 반환합니다.

따라서 {showCounter && <div className={classes.value}>{counter}</div>}에서는 showCounter가 true일 때만 <div className={classes.value}>{counter}</div> 부분이 평가되어 나타납니다. 만약 showCounter가 false이면, false로 평가되고 두 번째 피연산자인 <div> 부분은 무시됩니다.

이런 방식으로 코드를 작성하면 showCounter의 값에 따라 특정 부분을 간결하게 표현할 수 있습니다. 이는 조건부 렌더링을 위한 일반적인 JavaScript의 표현 방식 중 하나입니다.

 

✅ 토글카운터를 누르면 숫자가 사라짐.

 

 

  어떤 속성을 바꿔줄때 다른 속성을 챙기지 않으면 그 안챙겨준 값들은 없는 값들로 된다.


지금 counterReducer에는 2개의 속성이 있음.
{counter: 0, showCounter:true}


    if(action.type === 'toggle'){
        return {
            showCounter: !state.showCounter,
        }
    }

여기에는 toggle이라는 타입에 액션을 했을 때 리턴으로 showCounter를 보여주고 있는데
이 말은 counter라는 속성이 없어진거임. redux는 리듀서로 state바꿀때마다
새로운 state 덮어써서 counter는 undefined가 됨 그래서 안보이는거임.

 

before

 

import {createStore} from 'redux'

const counterReducer = (state = {counter : 0, showCounter: true}, action) => {
    if(action.type === 'increment'){
        return {
            counter: state.counter + 1
        }
    }

    if(action.type === 'decrement'){
        return {
            counter: state.counter - 1
        }
    }



    if(action.type === 'increase'){
        return {
            counter: state.counter + action.amount
        }
    }

    if(action.type === 'toggle'){
        return {
            showCounter: !state.showCounter,
        }
    }
    return state;


   
}

const store = createStore(counterReducer);

export default store;

 

 

✅그래서 카운터 1씩 다 올리고 토글 카운터 하고 나서 다시 펼쳐도 카운터 그대로 있다.

✅다른 if문들도 다른 state 다 챙겨야하는데, 다른 데서는 느낌표 없어야함.

 

import {createStore} from 'redux'

const counterReducer = (state = {counter : 0, showCounter: true}, action) => {
    if(action.type === 'increment'){
        return {
            counter: state.counter + 1,
            showCounter: state.showCounter,
        }
    }

    if(action.type === 'decrement'){
        return {
            counter: state.counter - 1,
            showCounter: state.showCounter,
        }
    }



    if(action.type === 'increase'){
        return {
            counter: state.counter + action.amount,
            showCounter: state.showCounter, /*이 위의 애들도 다 해줘야함*/
        }
    }

    if(action.type === 'toggle'){
        return {
            counter: state.counter,
            showCounter: !state.showCounter,
        }
    }
    return state;


   
}

const store = createStore(counterReducer);

export default store;

 

 

✅ 그냥...state하면 된다. 

 

 

그리고 또다른 방법은
속성이 2개밖에 없을 때는 일일이 추가해주는게 어렵지않아요.
state의 모든 값이 바뀔 수 있겠지만
어떤 값은 안 바뀌고 어떤 값은 바뀌고 그럴 수 있는데
...를 이용해서 바뀌는 값만 바꿔주게 한다. 안 바뀐 값은 그대로 기존 값 유지

 

import {createStore} from 'redux'

const counterReducer = (state = {counter : 0, showCounter: true}, action) => {
    if(action.type === 'increment'){
        return {
            ...state,
            counter: state.counter + 1,
        }
    }

    if(action.type === 'decrement'){
        return {
            ...state,
            counter: state.counter - 1,
        }
    }



    if(action.type === 'increase'){
        return {
            ...state,
            counter: state.counter + action.amount,
        }
    }

    if(action.type === 'toggle'){
        return {
            ...state,
            showCounter: !state.showCounter,
        }
    }
    return state;


   
}

const store = createStore(counterReducer);

export default store;
반응형