[Redux] React-router-dom과 함께 쓰기
connected-react-router
# terminal
$ npm i react-router-dom
// src/App.js
import "./App.css";
import { Router, Route } from "react-router-dom";
import Home from "./pages/Home";
import Todos from "./pages/Todos";
import Users from "./pages/Users";
import history from "./history";
function App() {
return (
<Router history={history}>
<Route path="/" exact component={Home} />
<Route path="/todos" exact component={Todos} />
<Route path="/users" exact component={Users} />
</Router>
);
}
export default App;
// src/pages/Home.jsx
import { Link } from "react-router-dom";
export default function Home() {
return (
<div>
<h1>Home</h1>
<ul>
<li>
<Link to="/todos">Todos</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</div>
);
}
// src/pages/Todos.jsx
import TodoFormContainer from "../containers/TodoFormContainer";
import TodoListContainer from "../containers/TodoListContainer";
export default function Todos() {
return (
<div>
<TodoListContainer />
<TodoFormContainer />
</div>
);
}
// src/pages/Users.jsx
import UserListContainer from "../containers/UserListContainer";
export default function Users() {
return (
<div>
<UserListContainer />
</div>
);
}
// src/redux/store.js
import { applyMiddleware, createStore } from "redux";
import todoApp from "./modules/reducer";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";
import history from "../history";
const store = createStore(
todoApp,
composeWithDevTools(
applyMiddleware(thunk.withExtraArgument({ history }), promise)
)
);
export default store;
// src/history.js
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
// src/containers/UserListContainer.jsx
import { useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import UserList from "../components/UserList";
import { getUsersThunk } from "../redux/modules/users";
export default function UserListContainer() {
const users = useSelector((state) => state.users.data);
const dispatch = useDispatch();
const getUsers = useCallback(() => {
dispatch(getUsersThunk());
}, [dispatch]);
return <UserList users={users} getUsers={getUsers} />;
}
// src/redux/modules/users.js
import axios from "axios";
export const GET_USERS_START = "redux-start/users/GET_USERS_START";
export const GET_USERS_SUCCESS = "redux-start/users/GET_USERS_SUCCESS";
export const GET_USERS_FAIL = "redux-start/users/GET_USERS_FAIL";
// redux-promise-middleware
const GET_USERS = "redux-start/users/GET_USERS";
export const GET_USERS_PENDING = "redux-start/users/GET_USERS_PENDING";
export const GET_USERS_FULFILLED = "redux-start/users/GET_USERS_FULFILLED";
export const GET_USERS_REJECTED = "redux-start/users/GET_USERS_REJECTED";
// 액션 생성 함수
export function getUsersStart() {
return {
type: GET_USERS_START,
};
}
export function getUsersSuccess(data) {
return {
type: GET_USERS_SUCCESS,
data,
};
}
export function getUsersFail(error) {
return {
type: GET_USERS_FAIL,
error,
};
}
// 초기값
const initialState = {
loading: false,
data: [],
error: null,
};
// 리듀서
export default function reducer(state = initialState, action) {
if (action.type === GET_USERS_START || action.type === GET_USERS_PENDING) {
return {
...state,
loading: true,
error: null,
};
}
if (action.type === GET_USERS_SUCCESS) {
return {
...state,
loading: false,
data: action.data,
};
}
if (action.type === GET_USERS_FULFILLED) {
return {
...state,
loading: false,
data: action.payload,
};
}
if (action.type === GET_USERS_FAIL) {
return {
...state,
loading: false,
error: action.error,
};
}
if (action.type === GET_USERS_REJECTED) {
return {
...state,
loading: false,
error: action.PAYLOAD,
};
}
return state;
}
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, ms);
});
}
// redux-thunk
export function getUsersThunk() {
return async (dispatch, getState, { history }) => {
try {
console.log(history);
dispatch(getUsersStart());
// sleep
await sleep(2000);
const res = await axios.get("https://api.github.com/users");
dispatch(getUsersSuccess(res.data));
history.push("/");
} catch (error) {
dispatch(getUsersFail(error));
}
};
}
// redux-promise-middleware
export function getUsersPromise() {
return {
type: GET_USERS,
payload: async () => {
const res = await axios.get("https://api.github.com/users");
return res.data;
},
};
}
# terminal
$ npm i connected-react-router
// src/redux/modules/reducer.js
import { combineReducers } from "redux";
import todos from "./todos";
import filter from "./filter";
import users from "./users";
import { connectRouter } from "connected-react-router";
import history from "../../history";
const reducer = combineReducers({
todos,
filter,
users,
router: connectRouter(history),
});
export default reducer;
// src/redux/store.js
import { applyMiddleware, createStore } from "redux";
import todoApp from "./modules/reducer";
import { composeWithDevTools } from "redux-devtools-extension";
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";
import history from "../history";
import { routerMiddleware } from "connected-react-router";
const store = createStore(
todoApp,
composeWithDevTools(
applyMiddleware(
thunk.withExtraArgument({ history }),
promise,
routerMiddleware(history)
)
)
);
export default store;
// src/App.js
import "./App.css";
import { Router, Route } from "react-router-dom";
import Home from "./pages/Home";
import Todos from "./pages/Todos";
import Users from "./pages/Users";
import history from "./history";
import { ConnectedRouter } from "connected-react-router";
function App() {
return (
<ConnectedRouter history={history}>
<Route path="/" exact component={Home} />
<Route path="/todos" exact component={Todos} />
<Route path="/users" exact component={Users} />
</ConnectedRouter>
);
}
export default App;
// src/pages/Home.jsx
import { push } from "connected-react-router";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
export default function Home() {
const dispatch = useDispatch();
return (
<div>
<h1>Home</h1>
<ul>
<li>
<Link to="/todos">Todos</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
<button onClick={click}>todos로 이동</button>
</div>
);
function click() {
dispatch(push("/todos"));
}
}
댓글남기기