- components/app.js
import React from "react"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; import Home from "../routes/Home"; import Detail from "../routes/Detail";function App() { return ( <Router> <Routes> <Route path="/" element={<Home />} /> <Route path="/:id" element={<Detail />} /> </Routes> </Router> ); }export default App;변경사항 1) Router > Routes > Route
변경사항 2) component 대신 element, 안에는 컴포넌트 형식으로 작성
- index.js
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./components/App";const root = ReactDOM.createRoot(document.getElementById("root"));root.render(<App />);변경사항 1) 선언하여 따로 빼줌, react-dom/client에서 불러옴
- routes/Home
import React from "react"; import { useState } from "react";function Home() { const [text, setText] = useState(""); function onChange(e) { setText(e.target.value); } function onSubmit(e) { e.preventDefault(); setText(""); console.log(text); } return ( <> <h1>To Do</h1> <form onSubmit={onSubmit}> <input type="text" value={text} onChange={onChange} /> <button>Add</button> </form> <ul></ul> </> ); }export default Home;
import { createStore } from "redux";
const ADD = "ADD";
const DELETE = "DELETE";
export const addToDo = (text) => {
return {
type: ADD,
text,
};
};
export const deleteToDo = (id) => {
return {
type: DELETE,
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 !== action.id);
default:
return state;
}
};
const store = createStore(reducer);
export default store;
index.js에 Provider 추가해서 store를 연결
...
import { Provider } from "react-redux";
import store from "./store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
=> Provider은 store가 필요함
Home에서 state를 가져와서 ul에 그려줘야 한다.
그러면 react-redux에서는 어떻게 state에 접근을 하는가?
- componenet들을 store에 연결시켜 줌
- connect는 두 개의 argument를 가짐
=> state
=> dispatch
connect의 첫 번째 argument
state와 props를 가져오는 함수
...
import { connect } from "react-redux";
...
function mapStateToProps(state, ownProps) {
return { toDos: state };
}
export default connect(mapStateToProps)(Home);
argument 1) store에 있는 state
argument 2) component의 props
=> 함수에 return {key: value} 형식으로 작성하면 props가 추가됨
dispatch는 어떻게 하는가?
connect의 두 번째 argument
dispatch를 전달할 수 있는 함수
=> 이걸 사용한 후부터는 props를 바꿀 수 있게 됨
...
function mapDispatchToProps(dispatch, ownProps) {
return { addToDo: (text) => dispatch(actionCreators.addToDo(text)) };
}
export default connect(mapStateToProps, mapDispatchToProps)(Home);
react hook을 사용해서 connect(mapStateToProps, mapDispatchToProps)를 사용하지 않고 state를 가져오고 dispatch를 하는 것
현재는 connect를 사용하지 않고 useSelector와 useDispatch를 사용함
useSelector
getState랑 똑같은 기능(store에서 정보를 가져옴)이고 리액트에서는 mapStateToProps 대체
useDispatch
mapDispatchToProps 대체
import React, { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { addToDo } from "../store";
function Home() {
const [text, setText] = useState("");
const toDo = useSelector((state) => state);
const dispatch = useDispatch();
function onChange(e) {
setText(e.target.value);
}
function onSubmit(e) {
e.preventDefault();
console.log(text);
setText("");
dispatch(addToDo(text));
}
return (
<>
<h1>To Do</h1>
<form onSubmit={onSubmit}>
<input type="text" value={text} onChange={onChange} />
<button>Add</button>
</form>
<ul>{toDo.map((a) => JSON.stringify(a))}</ul>
</>
);
}
export default Home;
import React from "react";
function ToDo ({text}) {
return (
<li>
{text}
<button>DEL</button>
</li>
)
}
export default ToDo;
...
import ToDo from "../components/ToDo";
...
return (
...
<ul>
{toDo.map((td) => (
<ToDo {...td} key={td.id}/>
))}
</ul>
)
=> key 값은 중복되지 않는 값으로 적기
=> 위와 같이 코드를 작성하면 todo 옆에 DEL 버튼이 함께 생성됨
import React from "react";
import { useDispatch } from "react-redux";
import { deleteToDo } from "../store";
function ToDo ({text, id}) {
const dispatch = useDispatch();
const onClick = () => {
dispatch(deleteToDo(id))
}
return (
<li>
{text} <button onClick={onClick}>DEL</button>
</li>
)
}
export default ToDo;
...
import { Link } from "react-router-dom";
...
return (
<li>
<Link to={`/${id}`}>
{text} <button onClick={onClick}>DEL</button>
</Link>
</li>
);
...
import React from "react";
import { useParams } from "react-router-dom";
function Detail() {
const id = useParams().id;
return <h1>Detail</h1>;
}
export default Detail;
=> useParams로 가져온 id는 path parameter의 정보임
import React from "react";
import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";
function Detail() {
const id = useParams().id;
const toDos = useSelector((state) => state);
const toDoText = toDos.find((toDo) => toDo.id === parseInt(id));
return (
<>
<h1>{toDoText?.text}</h1>
<h5>Created at : {toDoText?.id}</h5>
</>
);
}
export default Detail;