new Date().getTime() => Date.now() => crypto.randomUUID() 순으로 변경아직 해설을 보지 못 했기에 스탠다드반 수업 때 들은 걸 토대로 수정을 해보았다.
좀 더 간단하게 단축속성명으로 변경했다.
const newTodo = {
id: new Date().getTime(),
title,
body,
isDone: false,
};
굳이 부모 컴포넌트에 있을 필요가 없고 TodoForm에서만 쓰이기 때문에 TodoForm 내부로 이동시켜주었다.
const TodoForm = ({ todo, setTodo }) => {
const addTodoHandler = (e) => {
e.preventDefault();
if (!title || !body) {
alert("제목과 내용을 모두 채워주세요.");
return;
}
const newTodo = {
id: new Date().getTime(),
title,
body,
isDone: false,
};
setTodo([...todo, newTodo]);
setTitle("");
setBody("");
};
const [title, setTitle] = useState("");
const [body, setBody] = useState("");
return (
<form onSubmit={addTodoHandler} className="todoForm" type="submit">
<label>제목</label>
<input
type="text"
value={title}
onChange={(e) => {
setTitle(e.target.value);
}}
/>
<label>내용</label>
<input
type="text"
value={body}
onChange={(e) => {
setBody(e.target.value);
}}
/>
<Button>추가하기</Button>
</form>
);
};
본래는 그냥 전체 코드를 한꺼번에 넣어주었는데, h2 내 이름, 필터링 요소, TodoItem 버튼 텍스트 제외하곤 반복되는 코드이기에 하나의 코드로 나타낼 수 있도록 변경해주었다.
const TodoList = ({ isDone, todo, deleteTodoHandler, toggleTodoHandler }) => {
return (
<>
<h2>{isDone ? "Done" : "Working"}</h2>
<ul>
{todo
.filter((todo) => {
return todo.isDone === isDone;
})
.map(function (todo) {
return (
<TodoItem
key={todo.id}
todo={todo}
deleteTodoHandler={deleteTodoHandler}
toggleTodoHandler={toggleTodoHandler}
text={isDone ? "취소" : "완료"}
/>
);
})}
</ul>
</>
);
};
기존의 코드는 빈 값을 계속 넣어주면 코드가 실행되는 문제점이 있어 trim()을 통해 문제를 해결하였다.
if (!title.trim() || !body.trim()) {
alert("제목과 내용을 모두 입력해주세요.");
return;
}
해설 영상을 통해 Layout 컴포넌트를 따로 만들어주는 방법도 있다는 점을 알게되어 똑같이 제작해보았다.
const Layout = ({ children }) => {
return <div className="wrap">{children}</div>;
};
export default Layout;
어찌 보면 기본적인 것인데 놓치고 있었던 부분. placeholder를 넣어주었다.
<label>제목</label>
<input
type="text"
placeholder="제목을 입력해주세요."
name="title"
/>
<label>내용</label>
<input
type="text"
placeholder="내용을 입력해주세요."
name="body"
/>
제어/비제어 컴포넌트에 대해 배웠고 비제어 컴포넌트를 만드는 방법을 알게 되어 코드를 비제어 컴포넌트로 바꿔보았다.
const addTodoHandler = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const title = formData.get("title");
const body = formData.get("body");
if (!title.trim() || !body.trim()) {
alert("제목과 내용을 모두 입력해주세요.");
return;
}
const newTodo = {
id: crypto.randomUUID(),
title,
body,
isDone: false,
};
setTodos((prevTodos) => [...prevTodos, newTodo]);
e.target.reset();
};
new Date().getTime() => Date.now() => crypto.randomUUID() 순으로 변경id를 스탠다드반 수업 때 튜터님이 추천하신 Date.now() 로 바꿨다가, 해설 영상에 나온 crypto.randomUUID()로 바꿨다. 여러가지 방법을 알게 됐는데 상황에 따라 적절히 사용하면 될 것 같다.
const newTodo = {
id: crypto.randomUUID(),
title,
body,
isDone: false,
};
단수, 복수를 제대로 써줘야한다는 점은 금일 여러 번 강조를 받았다. 안 그래도 코드를 짜면서 이 부분이 명확하지 않아 좋지 못하다고 생각했는데, 복수형으로 바꾸면서 더 필요성을 강하게 느꼈다.
const [todos, setTodos] = useState([...])
두 정수 X, Y의 임의의 자리에서 공통으로 나타나는 정수 k(0 ≤ k ≤ 9)들을 이용하여 만들 수 있는 가장 큰 정수를 두 수의 짝꿍이라 합니다(단, 공통으로 나타나는 정수 중 서로 짝지을 수 있는 숫자만 사용합니다). X, Y의 짝꿍이 존재하지 않으면, 짝꿍은 -1입니다. X, Y의 짝꿍이 0으로만 구성되어 있다면, 짝꿍은 0입니다.
예를 들어, X = 3403이고 Y = 13203이라면, X와 Y의 짝꿍은 X와 Y에서 공통으로 나타나는 3, 0, 3으로 만들 수 있는 가장 큰 정수인 330입니다. 다른 예시로 X = 5525이고 Y = 1255이면 X와 Y의 짝꿍은 X와 Y에서 공통으로 나타나는 2, 5, 5로 만들 수 있는 가장 큰 정수인 552입니다(X에는 5가 3개, Y에는 5가 2개 나타나므로 남는 5 한 개는 짝 지을 수 없습니다.)
두 정수 X, Y가 주어졌을 때, X, Y의 짝꿍을 return하는 solution 함수를 완성해주세요.
이 문제는 시간 초과가 관건인 문제였다. 코드 자체에 문제가 있는 것은 아니었지만, 테스트 케이스 5곳에서 시간 초과 때문에 실패해서, 시간 복잡도를 줄이는데 초점을 맞춰야 했다.
처음에 제출한 코드는 다음과 같다.
function solution(X, Y) {
let result = [];
[...X].forEach((item)=>{
if (Y.includes(item)){
result.push(item);
Y = Y.replace(item, "");
}
})
if (result.length === 0){
return "-1";
} else if (result.join("").replaceAll("0","")===""){
return "0";
} else {
return result.sort((a,b)=>b-a).join("");
}
}
알맞게 풀었지만, X와 Y의 길이가 최대 3,000,000이기에, 그만큼 길 경우 반복을 상당히 많이 해줘야하는 점에서 시간 복잡도가 미친듯이 올라간다. (X*Y 만큼 해줘야 한다.)
그래서 여러가지 방법을 시도해 보았지만, 시간 복잡도가 달라질만한 방법을 찾지는 못 했다. 그렇게 질문하기 페이지도 전전하다가, "그냥 한 번의 순회로 각 숫자들의 개수를 세는게 낫"다는 힌트를 발견하고, 그렇게 할 수 있는 방법을 모색해 보았다.
머리를 싸매다가 결국 구글링으로 힌트를 얻은 후, 구조를 이해하고 내 방식대로 작성했다...
function solution(X, Y) {
let arrX = [...X]
let arrY = [...Y]
let result = "";
for (let i = 0; i< 10; i++){
let lengthX = arrX.filter((num)=>Number(num)===i).length;
let lengthY = arrY.filter((num)=>Number(num)===i).length;
if (lengthX > 0 && lengthY > 0 ){
result += String(i).repeat(Math.min(lengthX,lengthY));
}
}
if (result.length === 0){
return "-1";
} else if (result.replaceAll("0","")===""){
return "0";
} else {
return result.split("").sort((a,b)=>b-a).join("");
}
}
반복문을 사용해, 각 숫자가 X 및 Y에 들어있는 숫자만큼을 가져온 후, 둘 중 하나라도 0개 이상이라면 둘 중 작은 숫자만큼 i를 result에 추가한다. (사실 이 조건문은 굳이 필요 없지만, 추가하면 시간 복잡도가 줄어들기에 넣었다.)
이 방식대로 하면 기존의 X\*Y 만큼의 시간 복잡도에서, X\*10 + Y\*10으로 확 줄어들 수 있다.
처음에 잡은 감을 과감하게 다시 생각할 수 있어야한다는 점을 깨달은 문제였다... 오랫동안 풀리지 않는다면 기존 코드에서 어떻게 해보려고 하기 보다는 과감하게 다시, 다르게 해보는 것. 그게 이런 경우에는 중요한 것 같다.
자바스크립트 30제를 진행하면서 역시 Promise, async/await에서 어려움을 겪었는데 이번에 푼 문제가 앞으로도 도움이 될 것 같아 여기에 남겨두려고 한다.
function fetchAndPrintJson(url) {
return fetch(url)
.then((response) => {
return response.json()
})
.then((data) => {
console.log(data);
});
}
fetchAndPrintJson('https://jsonplaceholder.typicode.com/posts/1');
function fetchAndPrintJson(url) {
return fetch(url)
.then((response) => {
return response.json()
})
.then((data) => {
console.log(data);
});
}
fetchAndPrintJson('https://jsonplaceholder.typicode.com/posts/1');