리덕스 내용 정리
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)
}
})
위의 모든 코드가 이런 식으로 표현 가능
Author And Source
이 문제에 관하여(리덕스 내용 정리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@gouz7514/리덕스-내용-정리저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)