프론트엔드 첫걸음

Redux 본문

개발 공부/React

Redux

차정 2022. 8. 23. 12:27

컴포넌트들이 props 없이 state 공유할 수 있다.
Redux로 컴포넌트간 공유가 편해짐 - 대용량 프로젝트에 사용하면 좋다.

액션
- 상태에 어떤 변화가 필요할 때 만드는 것

{
  type : 'ADD_TODO',
  data : {
  	id : 1, 
    text : '리덕스 배우기',
  }
}

 

디스패치
- 액션을 발생시키는 함수. 액션을 파라미터로 넣어서 호출하면 스토어가 리듀서 함수를 실행함.

스토어
- 프로젝트에 리덕스를 적용하기 위해 만드는 저장공간. 한 개의 프로젝트는 하나의 스토어만 가짐.
   스토어 안에는 현대 애플리케이션 상태와 리듀서가 들어있으며, 그 외에도 몇가지 중요한 내장함수를 지닌다.

리듀서
- 변화를 일으키는 함수.  디스패치로 리듀서가 실행되면 현재상태와 액션을 파라미터로 받아와서 두 값으로 새로운 상태 만들어서 반환

const initialState = {
  counter: 1
};

function reducer(state = initialState, action) {
  switch (action.type) {
    case INCREMENT: 
      return {
        counter: state.counter + 1
      };
      
    default:
      return state;  
  }
}


구독
- 스토어의 내장함수 중 하나. subscribe 함수 안에 리스너 함수를 파라미터로 넣어서 호출해주면 
액션이 디스패치되어 상태가 업데이트 될 때마다 리스너 함수 호출 됨.

const listener = () => {
  console.log('상태가 업데이트 됨');
}

const unsubscribe = store.subscribe(listener);

unsubscribe(); // 추후 구독을 비활성화 할 때 함수를 호출

 

 

 

1. 세팅

Redux 라이브러리 설치

  1. package.json 에 설치된 react, react-dom 버전이 18.1 이상인지 확인
  2. 터미널에서 아래 명령어로 설치
    npm install @reduxjs/toolkit react-redux

store

store.js 파일생성

   import { configureStore } from '@reduxjs/toolkit'

   export default configureStore({
     reducer : {

     }
   })

index.js

index.js에서 Provider로 App 감싸주기

   <Provider store={store}>
      <App/>
   </Provider>

 

2. store에 State 보관하는 방법

createSlice에 nameinitialState 속성으로 state명과 초기 State 설정한다.
함수는 reducers라는 속성에 작성한다.

state 하나를 slice라고 부른다
export default configureStore의 reducer속성에 slice를 등록해줘야 사용이 가능하다.

  import { createSlice } from '@reduxjs/toolkit';

  //작성한 slice를 변수 user에 담아 export default configureStore의 reducer에 등록한다.
 
  let user = createSlice({
    name: 'user',
    initialState: { name: 'kim', age: 20 },
    reducers: {
      changeName(state) {
      
        //array,ojbect의 경우 state를 직접 수정해줘도
        state.name = 'park'; //immer.js도움
        // return { name: 'park', age: 20 };
      },
      
    increaseAge(state, action) {
      state.age += action.payload;
    },
      
      
    },
  });
  //함수 changeName 밖으로 빼서 export
  //user.actions 하면 reducers의 값으로 있던 함수들이 object형식으로 남는다.
  export let { changeName,increaseAge } = user.actions;

  //reducer의 객체에  '컴포넌트에서 사용할 slice명: slice명.reducer' 을 적어준다. 
  export default configureStore({
     reducer : {
       userStore: user.reducer
     }
   })

reducer에 createSlice의 속성명 name, initialState,
export default configureStore ({ reducer { 컴포넌트에서 사용할 slice명: slice명.reducer } }) 는 규칙이다.
매개변수는 action.payload 로 받는 것이 규칙이다. (두번째인수.payload가 규칙이나 통상적으로 두번째인수는 action이라고 작명함 )

   increaseAge(state, a) {
      state.age += a.payload;
    },

 

state 변경함수를 actions 라고 한다.

  export let { changeName,increaseAge } = user.actions;

user객체의 함수 (actions)에서 changeName, increasAge 함수를 export한다는 뜻이다.
export 해줘야 component에서 사용가능하다.

 

3. 컴포넌트에서 가져다 쓰기

useSelector 로 Redux의 store 가져와서 사용한다.
useSelector의 인수로 함수를 사용해야한다.
useDispatch는 store.js에 요청을 보내는 함수이다. 

  import { useSelector, useDispatch } from 'react-redux';

  function Cart() {
    let state = useSelector((state) => {
      return state;
    });
	//console.log(state) //userStore: {name: 'kim', age: 20}
    let dispatch = useDispatch();

    return (
      <div>
        <h6> {state.userStore.name}의 장바구니 </h6>
        <h6> {state.userStore.age}세 </h6>
        <button onClick={()=> {dispatch(increaseAge(10))}} </button>
      </div>
    );
  }

  export default Cart;

 

<button onClick={()=> {dispatch(increaseAge(10))}} </button>

increaseAge를 실행해달라고 요청(dispatch) 한다. 
increaseAge에 실어보내는 숫자 10을 화물(payload)이라고 여기면 된다.
dispatch로 store에 요청하고 store가 함수를 실행시키는 것이 복잡하고 큰 state를 관리하는 데 좋다.
모든 컴포넌트에서 state를 직접 변경하면, 어떤 컴포넌트에서 state를 잘못 변경시켰을 때
(state상태가 원하지 않는 값으로 변해버린 버그가 생겼을 때 )
state를 변경시킨 모든 컴포넌트를 다 확인해야한다. 하지만 store에서만 state를 수정하면, 
state가 잘못 변경되더라도 store만 확인하고, store만 고치면 되기때문에
redux로 state를 관리할 때에는 dispatch로 함수의 실행을 요청하는 방식을 사용한다.

 

 

참고

https://ko.redux.js.org/tutorials/fundamentals/part-1-overview/