리덕스 호출 > 리듀서를 호출한다.
const reducer = (state, action) => {}
store에 action을 전달하는 방법 > dispatch를 통해 store에 전달
action은 object형태로 전달되어야 함으로 {type : " " } 형태로 전달되어야 한다.
store.dispatch({type:"object"})
import {createStore} from 'redux'
//데이터를 수정하는 함수 (reducer)
const countModifier = (count = 0, action) => {
if (action.type == "ADD") {
return count+1;
} else if (action.type === "MINUS"){
return count -1;
}else{
return count;
}
}
const countStore = createStore(countModifier);
//데이터 변조를 위해 countModifier(reducer)에 메시지를(action)을 dispatch를 통해 보냄
countStore.dispatch({type:"ADD"})
countStore.dispatch({type:"ADD"})
countStore.dispatch({type:"ADD"})
countStore.dispatch({type:"ADD"})
countStore.dispatch({type:"MINUS"})
console.log(countStore.getState())
import {createStore} from 'redux'
//오타 방지를 위해 action type을 한곳에 정의
const ADD = "ADD";
const MINUS = "MINUS"
const add = document.getElementById("add");
const minus = document.getElementById("minus");
const number = document.querySelector("span");
let count = 0
number.innerText = count;
//reducer 는 함수이며, data를 수정한다
//createstore는 인자로 reducer를 요구한다
//여기서는 count 를 수정함
//return 하는 것은 너의 data를 리턴
const countModifier = (count, action) => {
//if else문을 switch로 변경
switch (action.type) {
case ADD:
return count + 1
case MINUS:
return count -1
default:
return count;
}
//action => count++, count-- 를 해주는 데이터를 변경시켜주는 형태
// if (action.type == "ADD") {
// return count+1;
// } else if (action.type === "MINUS"){
// return count -1;
// }else{
// return count;
// }
}
//createStore => state를 넣는 창고
//여기서 state == count 부분!!(바뀌는 부분)
//초기화된 값과 action을 불러온다.
const countStore = createStore(countModifier);
const onChange = () => {
console.log("change!!");
}
//subscribe을 통해 store내에 변화가 있으면 감지함
countStore.subscribe(onChange);
//이런식으로 써도 되고 아니면 아래 MINUs처럼 써도 된다(버튼을 연결하는 방법)
const handleAdd = () => {
countStore.dispatch({type:ADD})
}
//dispatch 를 버튼과 연결
add.addEventListener("click", handleAdd);
minus.addEventListener("click", () => countStore.dispatch({type:MINUS}));
//action을 modifier에 호출하는 방법 -> dispatch 를 사용
// countStore.dispatch({type:"ADD"})
// countStore.dispatch({type:"ADD"})
// countStore.dispatch({type:"ADD"})
// countStore.dispatch({type:"ADD"})
// countStore.dispatch({type:"MINUS"})
console.log(countStore.getState())
vanila
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);
주의 할점
const reducer = (state = [], action) => {
console.log(action);
switch (action.type) {
case ADD_TODO:
return []; //배열로서 반환
case DELETE_TODO:
return [];
default:
return state;
}
};
여기서
const reducer = (state = [], action) => {
console.log(action);
switch (action.type) {
case ADD_TODO:
state.push("sss") // 이런식으로 변경하지 말라는 뜻
case DELETE_TODO:
return [];
default:
return state;
}
};
대신에 이렇게 해라
const reducer = (state = [], action) => {
console.log(action);
switch (action.type) {
case ADD_TODO:
return [...state, {text:action.text}] // 새로운 object를 리턴해라
case DELETE_TODO:
return [];
default:
return state;
}
};
import { createStore } from "redux";
const form = document.querySelector("form");
const input = document.querySelector("input");
const ul = document.querySelector("ul");
const ADD_TODO = "ADD_TODO";
const DELETE_TODO = "DELETE_TODO";
//action type을 반환하는 객체 -> actionCreator
const addToDo = text => {
return {
type : ADD_TODO,
text
};
};
const deleteTodo = id => {
return {
type : DELETE_TODO,
id
};
};
//리듀서부분
const reducer = (state = [], action) => {
console.log(action);
switch (action.type) {
case ADD_TODO:
//리펙토링 부분
const newTodoObj = {text: action.text, id : Date.now()}
return [newTodoObj, ...state];
case DELETE_TODO:
const cleaned = state.filter(toDo => toDo.id !== action.id);
return cleaned;
default:
return state;
}
};
//스토어 생성
const store = createStore(reducer);
//스토어 구독
store.subscribe(() => console.log(store.getState()));
//디스패치 부분
const dispatchAddToDo = text => {
store.dispatch(addToDo(text));
};
const dispatchDeleteTodo = e => {
const id = parseInt(e.target.parentNode.id);
store.dispatch(deleteTodo(id))
}
//적용함수
const paintToDos = () => {
const toDos = store.getState();
//repaint시 모든것을 다 비우고(list)
ul.innerHTML = "";
//state에 있는 각각의 toDo를 이용해서 새로운 list를 만든다
toDos.forEach(toDo => {
const li = document.createElement("li");
const btn = document.createElement("button");
btn.innerText = "DEL";
btn.addEventListener("click", dispatchDeleteTodo)
li.id = toDo.id;
li.innerText = toDo.text;
li.appendChild(btn);
ul.appendChild(li);
});
};
store.subscribe(paintToDos);
const onSubmit = e => {
e.preventDefault();
const toDo = input.value; //들어온 값
input.value = "";
dispatchAddToDo(toDo);
};
form.addEventListener("submit", onSubmit);
import {createStore} from 'redux';
const ADD = "ADD";
const DELETE = "DELTE";
//action creator
const addToDo = (text) => {
return {
type : ADD,
text
};
};
const deleteToDo = (id) => {
return {
type : DELETE,
id : parseInt(id)
};
};
//리듀서
const reducer = (state = [], action) => {
switch(action.type) {
case ADD:
return [{text: action.text, id : Date.now()}, ...state];
case DELETE:
return state.filter(toDo => toDo.id !== action.id);
default:
return state;
}
};
//스토어 생성
const store = createStore(reducer);
export const actionCreatores = {
addToDo,
deleteToDo
}
export default store;
import React from "react";
import { HashRouter as Router, Route } from "react-router-dom";
import Home from "../routes/Home";
import Detail from "../routes/Detail";
function App() {
return (
<Router>
<Route path="/" exact component={Home}></Route>
<Route path="/:id" component={Detail}></Route>
</Router>
);
}
export default App;
import React from 'react'
//import { actionCreatores } from '../store';
import {remove} from "../store"
import { connect } from "react-redux";
import { Link } from "react-router-dom";
function ToDo({text, onBtnClick, id}) {
return (
<li>
<Link to={`/${id}`}>
{text}
</Link>
<button onClick={onBtnClick}>DEL</button>
</li>
)
}
function mapDispatchToProps(dispatch, ownProps){
return {
//onBtnClick : () => dispatch(actionCreatores.deleteToDo(ownProps.id))
onBtnClick : () => dispatch(remove(ownProps.id))
}
}
export default connect(null, mapDispatchToProps) (ToDo);
//클릭시 onBtnClick 함수 호출, -> 이 함수는 dispatch로 store.js의 action.creatores의 deleteTod
// -> deleteTodo는 type :DELETE, id : parsein(id)로 이 액션은 reducer로 전달
// -> reducer에서 액션 처리후 filtering된 상태를 반환하고 이 반환값을 ToDO 컴포넌트의 props로 추가함
import React from "react";
import { connect } from "react-redux";
function Detail({ toDo }) {
return (
<>
<h1>{toDo?.text}</h1>
<h5>Created at: {toDo?.id}</h5>
</>
);
}
function mapStateToProps(state, ownProps) {
const {
match: {
params: { id }
}
} = ownProps;
return { toDo: state.find(toDo => toDo.id === parseInt(id)) }; //params의 id 와 같은 첫번쨰 값을 반환
}
export default connect(mapStateToProps)(Detail);
import React, { useState } from "react";
import { connect } from "react-redux";
//import { actionCreatores } from "../store";
import {add} from "../store"
import ToDo from '../components/ToDo'
//store의 todos를 갖고옴(state)
//addToDo는 text를 인자로 받아서 store로 dispatch한것
function Home({ toDos, addToDo}) {
const [text, setText] = useState("");
function onChange(e) {
setText(e.target.value);
}
function onSubmit(e) {
e.preventDefault();
setText("");
addToDo(text)
}
return (
<>
<h1>To Do</h1>
<form onSubmit={onSubmit}>
<input type="text" value={text} onChange={onChange} />
<button>Add</button>
</form>
<ul>
{toDos.map(toDo => (
<ToDo {...toDo} key = {toDo.id} />
))}
</ul>
</>
);
}
//App.js의 router를 통해 store.js 의
//const reducer = (state = [], action) =>
//부분의 state(store의) 와 react-router를 통해 Home으로 전달받은 components의 ownprops를 받음
// function getCurrentState(state,ownProps)
// {
// console.log(state, ownProps);
// }
// //connect를 통해서 store.js에서 home으로 state를 갖고올것 이다
// export default connect (getCurrentState) (Home);
function mapStateToProps(state) {
return {toDos: state};
}
//home.js에 입력하면, store.js의 reducer로 dispatch 시킨다.
function mapDispatchToProps(dispatch){
//addTodo함수는 dispatch 시킴
return {
//addToDo: text => dispatch(actionCreatores.addToDo(text))
addToDo : text => dispatch(add(text))
}
}
// connect는 argument로 state와 dispatch를 가진다.
// ● mapStateToProps는 두 종류의 argument와 함께 호출되는 function이다.
// ▷ 첫번째 argument는 Redux store에서 온 state이다.
// ▷ 두번째 argument는 component의 props이다.
// ※connect()는 return한 것을 component의 prop에 추가해준다
export default connect(mapStateToProps, mapDispatchToProps)(Home);
import React from 'react'
import { actionCreatores } from '../store';
import { connect, useDispatch } from "react-redux";
import { Link } from "react-router-dom";
function ToDo({text,onBtnClick, id})
return (
<li>
<Link to={`/${id}`}>
{text} <button onClick={onBtnClick}>DEL</button>
</Link>
</li>
)
}
function mapDispatchToProps(dispatch, ownProps){
return {
onBtnClick : () => dispatch(actionCreatores.deleteToDo(ownProps.id))
}
}
export default connect(null, mapDispatchToProps) (ToDo);
import React from 'react'
import { actionCreatores } from '../store';
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
function ToDo({text, id}) {
const dispatch = useDispatch();
const onBtnClick = () => {
dispatch(actionCreators.deleteToDo(id));
}
return (
<li>
<Link to={`/${id}`}>
{text} <button onClick={onBtnClick}>DEL</button>
</Link>
</li>
)
}
export default ToDo;
import {createStore} from 'redux';
import {createAction,createReducer, configureStore, createSlice} from "@reduxjs/toolkit"
// //toolkit의 creatorAction으로 아래읰 코드들을 대체
// const addToDo = createAction("ADD")
// const deleteToDo = createAction("DELETE")
// // const ADD = "ADD";
// // const DELETE = "DELTE";
// //action creator
// // const addToDo = (text) => {
// // return {
// // type : ADD,
// // text
// // };
// // };
// // const deleteToDo = (id) => {
// // return {
// // type : DELETE,
// // id : parseInt(id)
// // };
// // };
// //toolkit으로 reducer 만들떈 state를 변경 할 수 있다.
// //return은 새로운 state를 반환할때 하는 것,
// //toolkit - reducer는 state를 변경하는것이기 때문에 return 하지 않음
// //현재 state = [] (비어있는 배열 )
// const reducer = createReducer([], {
// [addToDo] : (state, action) => {
// state.push({text:action.payload, id: Date.now()}); //push : 비어있는 배열에 새로운 값을 넣어준다.(새로운 배열 리턴 x) 중괄호 감쌈 () => {}
// },
// [deleteToDo] : (state, action) =>
// state.filter(toDo => toDo.id !== action.payload)//filter : 새로운 배열을 리턴함 중괄호 안쌈 () =>
// });
// //리듀서
// // const reducer = (state = [], action) => {
// // switch(action.type) {
// // case addToDo.type:
// // return [{text: action.payload, id : Date.now()}, ...state]; //인자값이 아닌 payload로 전달
// // case deleteToDo.type:
// // return state.filter(toDo => toDo.id !== action.payload); //action은 createAction 함수로 만들어지기 때문에 더이상 id를 갖고 있지 않아 payload로 변경
// // default:
// // return state;
// // }
// // };
//createSlice를 이용하여 reducer와 createAction을 합침
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)
}
})
const store = configureStore({reducer: toDos.reducer})
//slice에서 action까지 제공해줌
export const {
add,
remove
} = toDos.actions
// const store = configureStore({reducer})
// //스토어 생성
// // const store = createStore(reducer);
// export const actionCreatores = {
// addToDo,
// deleteToDo
// }
export default store;