<React> Redux toolkit

yezee·2022년 11월 3일
0

React

목록 보기
5/23
post-thumbnail

why Redux?
Redux는 props없이 state를 공유할 수 있게 도와주는 라이브러리
설치하면 js파일 하나에 state들을 보관할 수 있게된다!!
역시 시작은 설치! 설치하러 가보자~!

npm install @reduxjs/toolkit react-redux 를 터미널에 입력
(주의사항: package.json에서 "react", "react-dom" 가 18.1버전이상인지 꼭 확인해야한다)

리덕스 툴킷 세팅

  1. src폴더에 store.js파일을 만들어 아래 코드를 넣어준다
    앞으로 이 store.js파일은 state를 보관하는 파일이 된다
import {configureStore} from "@reduxjs/toolkit"

export default configureStore({
  reducer: {},
});
  1. index.js파일에 가서 Provider라는 컴포넌트와 아까 작성한 파일을 import한다
    <App/><Provider store={import해온것}></Provider>으로 감싼다
    이제 <APP>과 자식 컴포넌트들은 store.js에 있는 state를 맘대로 꺼내쓸게 있게 된다
import { Provider } from 'react-redux';
import store from './store.js';

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

store에 state보관하고 쓰는방법

1.createSlice()로 state만든다
2.configureStore()안에 등록한다

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

//usestate와 비슷한 역할
let user = createSlice({
  name: 'user', //name:"state이름"
  initialState: 'kim', //initialState:"state값"
});

//usestate와 비슷한 역할
let stock = createSlice({
  name: 'stock',
  initialState: [10, 11, 12],
});

//이 안에 등록한 state는 사용가능
export default configureStore({
  reducer: {
    user: user.reducer, //작명:createSlice변수명.reducer
    stock: stock.reducer,
  },
});

이제 store.js에 만든 state를 가져와보자

import {useSelector}from "react-redux"

function App(){
	let a=useSelector((state)=>state)
 }

App아래있는 모든 컴포넌트에서 useSlector((store)=>{return state})쓰면 store에 있던 모든 state가 자리에 남는다
a를 콘솔에 찍어보면 {user: 'kim', stock: Array(3)}이렇게 남는다

필요한 state만 콕 들고오고 싶으면?
let a=useSelector((state)=>state.stock)으로 state뒤에 가져오고 싶은 변수명을 넣어주면
(3) [10, 11, 12]이렇게 state에 넣어둔 값만 출력되는 것을 확인할 수 있다

store의 state를 변경하는 방법

usestate를 사용하면 상태변화함수를 포함하고 있어서 각 페이지에서 state를 변경하였다
하지만 리덕스를 사용하면 store.js에서 모든 함수를 만들고 불러다가 쓰는방식!
state변경함수를 만드는 순서는

  1. store.js에 state변경해주는 함수만든다
  2. export한다
  3. 필요한 페이지에서 함수명을 import하고 usedispatch도 import한다
    4.dispatch()로 state변경함수를 감싼다

....겁나 복잡하네???
하나하나 다시 살펴보자

첫째,
slice안에 reducers:{}열고 안에 state변경함수를 만들어 넣는다
변경함수이름(파라미터){return 변경사항}
이때 파라미터에는 이전 값을 넣을 수 있고 return에서 활용해서 사용할 수있다

둘째,
export를 한다
export let {변경함수이름}=변수이름.action

//usestate와 비슷한 역할
let user = createSlice({
  name: 'user',
  initialState: 'kim',

  reducers: {
    changeName(state) { //state는 기존 함수가 남는다("kim")
      return 'john'; //return 옆에 새로운 state를 입력하면 그걸로 기존 state를 갈아치운다
    },
  },
});

export let { changeName } = user.actions; //state변경함수들 남음

셋째,
변경함수를 원하는 페이지에서 import하기
넷째
dispatch(state변경함수())

import { useDispatch, useSelector } from 'react-redux'; //가져오기위한 라이브러리
import { changeName } from '../store'; //변경함수가져오기

function App() {
  let cartData = useSelector((state) => state.user); //리덕스 스토어에 있던 모든 state가 남음
  let dispatch = useDispatch(); //store.js로 요청을 보내주는 함수
  
  return(
    {state.user}의 장바구니
    <button onClick={dispatch(changeName())}>+</button>
  )
}

store의 state가 object/array인 경우 변경하는 방법

  • 기존 state를 가져와서 변경할 부분만 수정하기
//usestate와 비슷한 역할
let user = createSlice({
  name: 'user',
  initialState: {name:'kim', age:20}, //객체일때

  reducers: {
    changeName(state) { 
      return {name:"park",age:20} //변경할 부분만 바꿔서 넣는다
    },
  },
});
  • state를 직접수정하는 방법
    자동으로 내장된 lmmer.js라는 라이브러리가 state사본을 하나 더 생성해줘서 가능하다
//usestate와 비슷한 역할
let user = createSlice({
  name: 'user',
  initialState: {name:'kim', age:20}, //객체일때

  reducers: {
    changeName(state) { 
     	state.name="park"
    },
    changeAge(state){
    	state.age+=1
    }
  },
});

=>즉, array/object 자료의 경우 state를 직접 수정해버려도 잘 되니까 직접 수정하자!

그런대 state변경함수가 여러개 필요하면 어떻게해야하죠??가끔은 +10하는함수, +100하는 함수를 만들고 싶은대 똑같은걸 여러번 복제해야하나요??🤔🤔
정답은 파라미터 문법을 사용하면 됩니다

//usestate와 비슷한 역할
let user = createSlice({
  name: 'user',
  initialState: {name:'kim', age:20}, //객체일때

  reducers: {
    changeAge(state,action){
    	state.age+=action.payload
    }
  },
});

state가 기존값을 건들일 수 있는 파라미터라면 옆에있는
action은 값을 가져와서 가공할수이쓴 파라미터 입니다

<>
<h1>{state.user.name} {state.user.age}의 장바구니</h1>

<button onClick={()=>{dispatch(changeAge(100))}}>버튼</button>  
</>

changeAge()의 괄호안에 자리가 action.payload의 값이 들어가는 자리이다
따라서 위 코드에서 changeAge(100)을 넣었기 때문에 action.payload==100이 되고 나이가 100씩 증가하는 함수가 된다

redux를 reduxtoolkit으로 변경하여 비교해보기

기존 redux를 사용하면 store에 세팅해야할 것들이 많이 있다
combinereducer 합친 reducer를 store에 전달
thunk 미들웨어 사용을 위해 필요
applyMiddleware 미들웨어 사용을 위해 필요
composeWithDevTools 라이브러리
하지만
reduxtoolkit을 사용하게 되면 자동으로 세팅이 되어 있다

  • redux 사용
//productReducer.js
let initialState = {
  productList: [],
};

function productReducer(state = initialState, action) {
  let { type, payload } = action;
  switch (type) {
    case 'GET_PRODUCTS':
      return { ...state, productList: payload.data };
     default:
       return { ...state };
  }
}

 export default productReducer;

store에서 createStore를 사용해서 리덕스 사용

//store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index'; //reducer파일들을 전부 가지고 온다
import { composeWithDevTools } from 'redux-devtools-extension';

let store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(thunk))
);

export default store;

  • reduxtoolkit 사용
//productReducer.js
import {createSlice} from "@reduxjs/toolkit" //createSlice는 객체를 매개변수로 받는다 =>반드시 3개의 fild가 필요하다 

let initialState = {
  productList: [],
};

const productSlice=createSlice({ 
name:"product",
initialState,
reducers:{
    getAllProducts(state,action){
        state.productList=action.payload.data
    }
}
})

export const productActions= productSlice.actions
export default productSlice.reducer

store에서 configerStore사용해서 리덕스 사용

//store.js
import {configerStore} from "@reduxjs/toolkit"
import authenticateReducer from './reducers/authenticateReducer';
import productReducer from './reducers/productReducer';
import detailReducer from './reducers/detailReducer';

const store=configerStore({
    reducer:{ //index.js에서 작업한 combineReducer
        auth: authenticateReducer,
        product: productReducer,
        detail: detailReducer,
    }
})

export default store;

그럼 action은 어떻게 부를까요??
기존에는 type이름을 통해 전달하고 payload도 따로 작성해서 전달

function getProducts(searchQuery) {
  return async (dispatch, getState) => {
    let url = `http://localhost:3004/products?search=${searchQuery}`;
    let response = await fetch(url);
    let data = await response.json();
    dispatch({ type: 'GET_PRODUCTS', payload: { data } });
  };
}

최신 리덕스에서는 action을 impor하여 dispatch하는 방법을 사용
payload를 매개변수로 보낸다

import { productActions } from '../reducers/productReducer'; //type대신에 고유이름을 import해온다

function getProducts(searchQuery) {
  return async (dispatch, getState) => {
    let url = `http://localhost:3004/products?search=${searchQuery}`;
    let response = await fetch(url);
    let data = await response.json();
    dispatch(productActions.getAllProducts({data}));
  };
}

redux
dispatch({ type: 'GET_PRODUCTS', payload: { data } });


toolkit
dispatch(productActions.getAllProducts({data}));

profile
아 그거 뭐였지?

0개의 댓글