리덕스 내용 정리

45290 단어 리덕스리덕스

Redux란

0427

리덕스는 기본적으로 js application의 상태를 관리하는 방법

0505

먼저 Vanilla JS로 만들고 리덕스로 만들고 왜 리덕스 사용하는지 알아본다.
npm install redux로 리덕스 설치
이후

import {createStore} from "redux";

1. store
state는 어플리케이션에서 바뀌는 data. 현재 프로젝트에서는 count가 state
store가 하는 일은 기본적으로 data를 넣을 수 있는 장소를 생성

store 만들면 reducer 필요 (createStore는 reducer 필요)

2. reducer
reducer는 data를 modify하는 함수
reducer가 return하는 것이 어플리케이션의 state

// 오직 얘만 가지고 data를 modify한다.
const countModifier = () => {
  return "hello";
}

const countStore = createStore(countModifier);
console.log(countStore.getState()); // hello가 출력된다

store를 만들면 reducer를 initial state로 불러오고 modify한 뒤 return한다

3. action
reducer와 소통
action은 object여야 한다 (type 필요)
store -> dispatch -> action
리덕스가 reducer를 부르고 dispatch를 통해서 action 수행

const countModifier = (count = 0, action) => {
  if (action.type === "ADD") {
    count += 1;
  }
  return count;
}

const countStore = createStore(countModifier);
countStore.dispatch({type:"ADD"});
console.log(countStore.getState()); // 1

store 만들고 reducer 선언하고 message를 dispatch를 통해서 reducer에 보낸다

// 이런 식으로 store에 보낸다
add.addEventListener("click", () => {
  countStore.dispatch({type:"ADD"});
})
minus.addEventListener("click", () => {
  countStore.dispatch({type:"MINUS"});
})

subscribe
store 안에 있는 변화들을 알 수 있게 해줌

// store에 변화 생기면 onChange 실행 -> number 변경
const onChange = () => {
  number.innerText = countStore.getState();
}

countStore.subscribe(onChange);

0506

투두 리스트 만들기

// Vanilla jS
const form = document.querySelector("form");
const input = document.querySelector("input");
const ul = document.querySelector("ul");

const createToDo = toDo => {
  const li = document.createElement("li");
  li.innerText = toDo;
  ul.appendChild(li);
};

const onSubmit = e => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  createToDo(toDo);
}

form.addEventListener("submit", onSubmit);

이제 redux
사용자가 submit할 때, 리스트를 만들고 리스트 아이템들을 리스트에 넣어주는 createToDo를 호출하는 대신 dispatch로 처리

const onSubmit = e => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  store.dispatch({type: ADD_TODO, text: toDo});
}

state를 바꿀 수 있는 유일한 방법은 action
state를 수정하는 것이 아니라 새로운 state를 return

const reducer = (state = [], action) => {
  console.log(action);
  switch (action.type) {
    case ADD_TODO:
      return [...state, {text:action.text, id:Date.now()}]; // 여기가 중요!
      // state를 수정하지 않고 새로운 state return
    case DELETE_TODO:
      return [];
    default:
      return state;
  }
}

addToDo

const store = createStore(reducer);

store.subscribe(() => console.log(store.getState()));

const paintToDos = () => {
  const toDos = store.getState();
  ul.innerHTML = "";
  toDos.forEach(toDo => {
    const li = document.createElement("li");
    li.id = toDo.id;
    li.innerText = toDo.text;
    ul.appendChild(li);
  })
}

store.subscribe(paintToDos);


const addToDo = (text) => {
  store.dispatch({type: ADD_TODO, text});
}

const onSubmit = e => {
  e.preventDefault();
  const toDo = input.value;
  input.value = "";
  addToDo(toDo);
}

form.addEventListener("submit", onSubmit);

deleteTodo
JS에서 splice를 쓸 경우 배열이 변하게 된다. 즉, 상태가 변경됨
따라서, filter를 사용

// action creator : object를 return하는 function
const deleteToDo = id => {
  return {
    type:DELETE_TODO,
    id
  }
}

const reducer = (state = [], action) => {
  switch (action.type) {
    case ADD_TODO:
      return [...state, {text:action.text, id:Date.now()}];
    case DELETE_TODO:
      return state.filter(toDo => toDo.id !== action.id);
    default:
      return state;
  }
}
...
const dispatchDeleteToDo = (e) => {
  const id = parseInt(e.target.parentNode.id);
  store.dispatch(deleteToDo(id));
}

0507

react-redux setup
커밋 보기

이후 store와 연결 과정 진행
(앞 부분은 이전 과정과 동일)

우리가 원하는 건 store를 subscribe
뭔가 변화가 일어나면 application을 다시 render하고 싶다
여기서 필요한 것이 react-redux

Provider
React Redux - Provider
index.js에서 내 application을 store에 연결하는데 사용

import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";
import {Provider} from "react-redux";
import store from "./store";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

Home.js<ul></ul> 부분에서 store로부터 state를 가져와야 함
여기서 등장하는 놈이 바로 connect
components를 store에 연결시킨다
component로 보내는 props에 추가할 수 있도록 허용

mapStateToProps()를 사용해서 store로부터 state를 Home에 갖다준다
mapStateToProps()는 2개의 argument 필요
하나는 store로부터 온 state, 그리고 component의 props

// 첫번째 argument는 redux store에서 온 state
// 두번째는 component의 props : react-router에 의해 Home에 주어진 props
function mapStateToProps(state) {
  return {toDos: state}; // 여기서 return하면 Component의 prop에 추가된다
}

0510

mapDispatchToProps()
component가 dispatch 동작 할 수 있도록 한다.
connect의 두번째 인자로 들어감

// store.js 수정
export const actionCreatros = {
  addToDo,
  deleteToDo
};
// Home.js
function mapDispatchToProps(dispatch) {
  return {
    addToDo : (text) => dispatch(actionCreatros.addToDo(text))
  }
}

addToDo라는 함수는 text argument가 필요하고 이 함수가 실행되면 actionCreators.addToDo()와 함께 dispatch 호출

Component로부터 reducer에게 dispatch

0512

// ToDo.js
import React from "react";
import { connect } from "react-redux";
import { actionCreatros } from "../store";

function ToDo({text, onBtnClick}) {
  return (
  <li>
    {text} <button onClick={onBtnClick}>DEL</button>
  </li>
  );
}

function mapDispatchToProps(dispatch, ownProps) {
  return {
    onBtnClick: () => dispatch(actionCreatros.deleteToDo(ownProps.id))
  }
}

export default connect(null, mapDispatchToProps) (ToDo);

ToDo에서는 state에 대해서는 신경 X. reducer에게 메시지 보내길 원함
ownProps에 text랑 id 들어있다

Detail screen
ToDo.js에서 ToDo를 Link로 감싸고

// Detail.js
import React from "react";
import { connect } from "react-redux";

function Detail({toDo}) {
  return <h1>{toDo?.text}</h1>;
}

function mapStateToProps(state, ownProps) {
  const {
    match:{
      params:{id}
    }
  } = ownProps; // = const id = ownProps.match.params.id;
  return {toDo:state.find(toDo => toDo.id === parseInt(id))};
}

export default connect(mapStateToProps) (Detail);

0513

Redux Tolkit

더 적은 양의 Redux 코드를 짤 수 있게 해줌

npm install @redusjs/toolkit

createAction
https://redux-toolkit.js.org/api/createAction

import {createAction} from "@reduxjs/toolkit";

const addToDo = createAction("ADD");
const deleteToDo = createAction("DELETE");
// ~.type으로 해당 텍스트 확인 가능

aciton에 무엇을 보내던 항상 payload와 함께 보내진다

createReducer
https://redux-toolkit.js.org/api/createReducer
switch문을 사용하지 않고
새로운 state를 return하거나 state를 mutate할 수 있다

const reducer = createReducer([], {
  [addToDo]: (state, action) => {
    state.push({text: action.payload, id:Date.now()}); // mutate state
  },
  [deleteToDo]: (state, action) =>
    state.filter(toDo => toDo.id !== action.payload); // return new state
})

you need to ensure that you either mutate the state argument or return a new state, but not both.

configureStore
https://redux-toolkit.js.org/api/configureStore
미들웨어와 함께 store 생성

createSlice
https://redux-toolkit.js.org/api/createSlice
reducer뿐 아니라 action도 생성

const toDos = createSlice({
  name:'toDosReducer',
  initialState: [],
  reducers: {
    add: (state, action) => {
      state.push({text: action.payload, id:Date.now()});
    },
    remove: (state, action) => 
      state.filter(toDo => toDo.id !== action.payload)
  }
})

위의 모든 코드가 이런 식으로 표현 가능

좋은 웹페이지 즐겨찾기