(23.07기준 v8)
npm install react-redux
npx create-react-app my-app --template redux
(23.07기준 v6)
npm install react-router-dom
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<title>Vanilla Redux</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./components/App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(<App />);
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../routes/Home";
import Detail from "../routes/Detail";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/:id" element={<Detail />} />
</Routes>
</BrowserRouter>
);
}
export default App;
🛠️참고) 강의에서는 v5의 react-router-dom으로 작성되었지만, 나는 v6 기준으로 작성하였다.
강의의 버전을 사용하고 싶다면npm install react-router-dom@5.1.2
를 설치하면 된다.
import React, { useState } from "react";
function Home() {
const [text, setText] = useState("");
function onChange(e) {
setText(e.target.value);
}
function onSubmit(e) {
e.preventDefault();
console.log(text);
setText("");
}
return (
<>
<h1>To Do</h1>
<form onSubmit={onSubmit}>
<input type="text" value={text} onChange={onChange} />
<button>Add</button>
</form>
<ul></ul>
</>
);
}
export default Home;
vanilla JS에서 만든 store파일과 똑같이 만든다.
import { legacy_createStore } from "redux";
const ADD = "ADD";
const DELETE = "DELETE";
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 }, ...state];
case DELETE:
return state.filter((toDo) => toDo.id !== action.id);
default:
return state;
}
};
const store = legacy_createStore(reducer);
// store(=data)변경사항을 알아차리고 변화가 일어난 부분의 Application을 re-render 하고싶다 => index.js에서 연결
store.subscribe();
export default store;
Provider
: React Redux에는 Provider컴포넌트를 통해 앱의 다른 컴포넌트에서 Redux store를 사용할 수 있다.
index.js
- Provider
추가
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./components/App";
import { Provider } from "react-redux"; // 추가
import store from "./store"; // 추가
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
root.render(
<Provider store={store}> // 컴포넌트를 감싼다.
<App />
</Provider>
);
component와 store를 연결시키기
store.dispatch()
? store.getState()
? getState()
기능 먼저 배우기connect
connect
: 나의 components들을 store에 연결시켜 줌mapStateToProps
: 두 종류의 argument와 함께 호출되는 function이다.connect
는 return한 것을 component의 prop에 추가해준다.mapStateToProps
추가import React, { useState } from "react";
import { connect } from "react-redux";
function Home({ toDos }) {
const [text, setText] = useState("");
function onChange(e) {
setText(e.target.value);
// ...중략...
<input type="text" value={text} onChange={onChange} />
<button>Add</button>
</form>
<ul>{JSON.stringify(toDos)}</ul>
</>
);
}
// mapStateToProps: Redux store에서 온 state을 받음
function mapStateToProps(state) {
return { toDos: state }; // []
}
// connect: Home.js를 store와 연결시킴
export default connect(mapStateToProps)(Home);
connect는 여전히 작동하며 React-Redux 8.x에서 지원된다. 그러나 기본적으로 hooks API를 사용하는 것이 좋다.
더 자세한 내용1
더 자세한 내용2
useSelector
추가import React, { useState } from "react";
import { useSelector } from "react-redux";
function Home(props) {
// **React Hook사용**
// useSelector를 통해 store의 state를 바로 가져옴
const toDos = useSelector((state) => state);
const [text, setText] = useState("");
function onChange(e) {
setText(e.target.value);
}
function onSubmit(e) {
e.preventDefault();
console.log(text);
setText("");
}
return (
<>
<h1>To Do</h1>
<form onSubmit={onSubmit}>
<input type="text" value={text} onChange={onChange} />
<button>Add</button>
</form>
<ul>{JSON.stringify(toDos)}</ul>
</>
);
}
export default Home;
dispatch()
기능의 mapDispatchToProps
🛠️이 섹션부터 앞으로 react Hooks를 사용하는 코드만 공유한다.
mapDispatchToProps
함수 활용은 강의 참고
useDispatch
추가import React, { useState } from "react";
import { connect, useDispatch, useSelector } from "react-redux";
import { addToDo } from "../store";
function Home(props) {
// **React Hook사용**
// useSelector를 통해 store의 state를 바로 가져옴 (getState기능)
const toDo = useSelector((state) => state);
// useDispatch는 mapDispatchToProps 대체: Redux store에서 dispatch 함수에 대한 참조를 반환
const dispatch = useDispatch();
const [text, setText] = useState("");
function onChange(e) {
setText(e.target.value);
}
function onSubmit(e) {
e.preventDefault();
dispatch(addToDo(text));
setText("");
}
return (
<>
<h1>To Do</h1>
<form onSubmit={onSubmit}>
<input type="text" value={text} onChange={onChange} />
<button>Add</button>
</form>
<ul>{JSON.stringify(toDo)}</ul>
</>
);
}
export default Home;
// ...생략
import ToDo from "../components/ToDo";
// .. 중략 ..
<ul>
{toDos.map((toDo) => (
{/* {...toDo}로 모든 정보 보냄 */}
<ToDo {...toDo} key={toDo.id} />
))}
</ul>
// 생략 ...
useDispatch
사용import React from "react";
import { useDispatch } from "react-redux";
import { deleteToDo } from "../store";
function ToDo({ text, id }) { // text, id 받아옴
const dispatch = useDispatch();
const onClick = (e) => {
const id = e.target.parentElement.id;
// deleteToDo는 store부터 받아옴
dispatch(deleteToDo(id));
};
return (
<li id={id}>
{text}
<button onClick={onClick}>DEL</button>
</li>
);
}
export default ToDo;
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom";
import { deleteToDo } from "../store";
function Detail() {
const id = useParams().id;
const toDos = useSelector((state) => state);
const toDo = toDos.find((todo) => todo.id === parseInt(id));
const dispatch = useDispatch();
const navigate = useNavigate();
const handleDel = () => {
dispatch(deleteToDo(id));
navigate(-1);
};
return (
<>
<h1>{toDo?.text}</h1>
<h5>Created at: {toDo?.id}</h5>
<button onClick={handleDel}>delete</button>
</>
);
}
export default Detail;
Link
추가import React from "react";
import { useDispatch } from "react-redux";
import { deleteToDo } from "../store";
import { Link } from "react-router-dom"; // 추가
function ToDo({ text, id }) {
const dispatch = useDispatch();
const onClick = (e) => {
const id = e.target.parentElement.id;
dispatch(deleteToDo(id));
};
return (
<li id={id}>
<Link to={`/${id}`}>{text}</Link> {/* 추가 */}
<button onClick={onClick}>DEL</button>
</li>
);
}
export default ToDo;
Array.prototype.find()
출처 : 노마드코더 - 초보자를 위한 리덕스 101