✏알고리즘 문제 풀이
programmers / level2 / 2 x n 타일링
동적계획법(Dynamic Programming)의 헬로월드같은 문제 타일링.
백준에서 오래전에 풀어본 적이 있지만, 오랜만에 리마인드하는 느낌으로 풀어봤다.
투두리스트 버전업하기
이 두가지를 추가해보자
1. redux로 전역상태관리 해주기
2. 디테일 페이지 만들기
버전 표기하기
git 버전 달기 (git tag)
버전 관리 규칙
Redux 관련 글
불변성을 지키면서 중복된 redux object를 업데이트하는 방법
function updateVeryNestedField(state, action) {
return {
...state,
first: {
...state.first,
second: {
...state.first.second,
[action.someId]: {
...state.first.second[action.someId],
fourth: action.someValue
}
}
}
}
}
redux 내부에서도 state의 불변성을 유지하며 업데이트했던 것처럼 동일하게 써주면 된다.
redux-toolkit에 불변성을 유지하면서 쉽게 업데이트해주는 기능이 있다고하니
toolkit을 배울 때 이 점을 기억하고 배우면 될 것 같다.
https://redux.js.org/usage/structuring-reducers/immutable-update-patterns#updating-nested-objects
투두리스트 redux 입문
투두리스트를 만들면서 redux를 입문한다면 참고하기 좋은 글이 될 것 같다.
Redux + localStorage 적용하기
Redux에서 지원해주는 기능으로 localStorage와 쉽게 연동할 수 있다.
dispatch가 일어날때마다 작동하는 subscribe 함수를 이용하면 된다.
import { createStore, combineReducers } from "redux";
import reducer from "../reducers";
const rootReducer = combineReducers({
...reducer
});
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
const store = createStore(rootReducer, persistedState);
store.subscribe(() => {
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
export default store;
두번째로는 redux-persist라는 라이브러리를 이용하면 된다.
Redux에는 localStorage와 연동하기 쉽게 관리해준다.
여러 데이터를 관리해야하거나 큰 프로젝트의 경우에는 redux-persist를 사용하고
데이터가 많지 않고 프로젝트가 작다면 subscribe를 이용하면 될 것 같다.
▶참고
Unique Id 생성하기
yyyymmddhhmmss의 형태로 아이디값을 생성했었는데
정상적인 방법으로 투두리스트를 생성한다면 아이디값이 중복되지 않지만
비정상적인 방법으로 1초내에 여러 투두리스트를 생성한다면 중복생성되게 된다.
여기에 여러 라이브러리로 방법을 대응
1. uuidv4
2. nanoId
3. _.uniqueId
4. react-id-generator
링크 컴포넌트 내부에 있는 버튼 처리
<StyledCard id={data.id}>
<Link to={`details/${data.id}`}>
<h1 className="title">{data.title}</h1>
<h3 className="content">{data.content}</h3>
<ButtonBox>
<Button>삭제</Button>
<Button>완료</Button>
</ButtonBox>
</Link>
</StyledCard>
링크 내부에 있는 버튼을 누르면 버튼 기능과 Link 기능이 동시에 일어나게 된다.
이럴때는 버튼 onClick 핸들러 함수에 preventDefault()이나 stopPropagation()을 추가해주면 된다.
추가로 stopPropagation은 이벤트 버블링을 방지하는 해결책으로 많이 사용하니 알아두면 좋다
▶참고
Button 컴포넌트로 들어오는 onClick함수가 동작하기 전에 event.preventDefault()를 추가하는 방식으로 해결했다.
const Button = ({ color, children, onClick }) => {
const handleClick = (event) => {
event.preventDefault();
onClick();
};
return (
<StyledBtn color={color} onClick={handleClick}>
<span>{children}</span>
</StyledBtn>
);
};
라우팅 구현하기
📃App.js
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Layout from './common/Layout';
import Details from './pages/Details';
import ToDoList from './pages/ToDoList';
function App() {
return (
<BrowserRouter>
<Layout>
<Routes>
<Route path="/" element={<ToDoList />} />
<Route path="details/:id" element={<Details />} />
</Routes>
</Layout>
</BrowserRouter>
);
}
export default App;
BrowserRouter > Routes > Route 순으로 컴포넌트를 사용해주어야 한다.
여담으로는 옛날에 HashRouter도 많이 사용했지만 #이 url에 붙어서 url이 못생겨진다고 안쓰게 됐다고 들었다.
홈페이지("/")는 투두리스트를 바로 보여주고
디테일 페이지는 id값에 따라 다르게 보여줘야하기 때문에 path="details/:id"로 설정해주었다,
const Details = () => {
const param = useParams();
const toDo = toDos.find((toDo) => toDo.id === param.id);
(...)
useParams 훅을 이용해서 url로 전달한 id 값을 읽어올 수 잇다.
뒤로가기 구현하기
react-router-dom 5버전까지만해도 useHistory를 이용해야했는데
push(path, [state]) - (function) Pushes a new entry onto the history stack
replace(path, [state]) - (function) Replaces the current entry on the history stack
go(n) - (function) Moves the pointer in the history stack by n entries
goBack() - (function) Equivalent to go(-1)
goForward() - (function) Equivalent to go(1)
block(prompt) - (function) Prevents navigation (see the history docs
// This is a React Router v5 app
import { useHistory } from "react-router-dom";
function App() {
let history = useHistory();
return (
<div>
<button onClick={() => {history.push("/main")}}>go home</button>
<button onClick={() => {history.goBack()}}>prev page</button>
<button onClick={() => {history.push(`/product/$parseInt(id)`)}}>detail page</button>
</div>
);
}
// This is a React Router v6 app
import { useNavigate } from "react-router-dom";
function App() {
let navigate = useNavigate();
return (
<div>
<button onClick={() => {navigate("/main")}}>go home</button>
<button onClick={() => {navigate(-1)}}>prev page</button>
<button onClick={() => {navigate(`/product/$parseInt(id)`)}}>detail page</button>
</div>
);
기존의 메소드를 여러가지 선언해야했던 방식에서 더 직관적이고 간결하게 변한 것 같아서 훨씬 편해보인다.
뒤로가기는 이렇게 쉽게 구현할 수 있다.
const navigate = useNavigate();
const handleGoBack = () => {
navigate(-1);
};
home으로 이동하는 것이라면 navigate("/") 해주어도 상관없다.
공식문서 들어가는 김에 다른 훅들도 살펴보면 좋을 것 같다.
▶공식문서
👻아무 말
이번 주차 투두리스트 요구사항은 전부 마무리했다.
그냥 제출해도 되는데,
뭔가 더 추가해야겠다는 마음이 들면서 미련이 많이 남는다.
너무 시간이 늦어서 추가사항은 내일 더 추가해야겠다.
시간은 많이 들였지만, 이것저것 찾아보면서 많이 배워서 뿌듯한 날
'개발일기' 카테고리의 다른 글
[TIL] 더 좋은 것을 위한 고민 (2) | 2022.12.09 |
---|---|
[TIL] 투두리스트 버전 2 (0) | 2022.12.08 |
[TIL] 끝까지 가는 놈이 이긴다 (1) | 2022.12.05 |
[TIL] 파산신청 직전입니다 (0) | 2022.12.03 |
[TIL] 결국 쓰러졌습니다 (4) | 2022.12.02 |