React/개념
투두리스트 구현 1
spring_sunshine
2022. 9. 23. 10:49
[React] 간단한 투두리스트 만들기
리액트를 다루는 기술 10장 일정 관리 웹 애플리케이션 만들기를 보면서 만든 투두리스트 앱입니다. 할 일 추가, 체크, 삭제 기능에 수정하기 기능을 덧붙였습니다.
velog.io
TodoTemplate, TodoInsert, TodoListItem, TodoList, TodoEdit 로 이루어져 있는 투두리스트를 만들 것이다.
기능 구현
우선 TodoTemplate 안에 입력창, 할일 목록들을 넣었다. JSX 형식으로 표현하면 이런 느낌이다.
<TodoTemplate> //앱을 이루는 컨테이너 박스
<ToDoInsert /> //할 일 입력창
<ToDoList> //할 일 목록(ul)
<ToDoListItem /> //할 일 (li)
</ToDoList>
<ToDoEdit /> //수정하기 창(팝업창이라서 대충 빼놓음)
</TodoTemplate>
일정 항목에서 필요한 것은 텍스트(내용), 체크박스, 삭제버튼, 수정버튼이다.
// id, text, checked 세가지의 key를 가진 객체로 구성하자
{
id: 1,
text: '리액트 기초',
checked: true,
}
TodoInsert
- 사용자의 할일을 입력받는 란, 추가버튼
form 태그
- 하나의 입력란과 제출버튼으로 구성된 간단한 양식은 <form> <input /> <button /> </ form> 으로 구성된다.
- 사용자의 입력을 React가 인지하고 통제할 수 있어야 한다. 이때 React의 useState()을 사용하여 상태를 추가해주고, 해당 상태값을 <input>의 value 속성에 설정해준다.
- 입력값이 바뀔때마다 발생하는 변경(Change) 이벤트를 처리하기 위한 handleChange() 함수를 <input>의 onChange 속성에 설정해준다.
- 제출버튼을 클릭하면 form에서 submit 이벤트가 발생한다. 해당 이벤트를 처리하기 위한 handleSubmit() 함수를 <form>의 onSubmit 속성에 설정해준다.
- 양식을 제출할 때는 브라우저에서 새로 고침이 일어나는데, SPA에서는 필요없는 동작이므로 handleSubmit() 함수 안에서 event.preventDefault() 로 해당 동작을 방지한다.
- 중복 제출 방지를 위해 사용자가 제출버튼을 클릭하자마자 제출버튼을 비활성화 시켰다가, 이벤트 처리가 완료됐을 때 제출버튼을 다시 활성화시키는 게 안전하다.
- 버튼 활성화 여부를 관리하는 disabled 상태를 추가하고, <button>의 disabled 속성에 설정해준다.
- 그리고 handleSubmit() 함수에서 disabled 값을 맨 처음에는 true로 변경했다가 맨 마지막에는 false로 변경한다.
- 마지막으로 제출 이벤트 처리시 발생하는 지연을 시뮬레이션 하기 위해 handleSubmit() 내에서 1초 지연을 발생시킨다.
const [disabled, setDisabled] = useState(false);
...
const handleSubmit = async (event) => {
setDisabled(true);
event.preventDefault();
await new Promise((r) => setTimeOut(r,1000));
alert(`변경된 패스워드: ${password}`);
setDisabled(false);
}
...
return (
...
<button type='submit' disabled={disabled}> 비번 변경 </button>
...
)
React로 양식(form) UI 구현하기
Engineering Blog by Dale Seo
www.daleseo.com
Promise
- new Promise(...)로 Promise 객체를 새로 만든다. 생성자는 특별한 함수(화살표 함수 형태) 하나를 인자로 받는다. 이 특별한 함수를 공식 문서에서는 executor라고 부른다. new Promise((resolve, reject) => { 비동기 작업 })
- executor의 첫번째 인수는 resolve, 두번째 인수는 reject 이다. resolve를 호출하게 되면 비동기 작업이 성공했다는 뜻이고, reject를 호출하게 되면 비동기 작업이 실패했다는 뜻이다.
- Promise의 특징은 new Promise(...) 하는 순간 여기에 할당된 비동기 작업이 바로 시작된다는 것이다. 작업이 끝난 이후의 동작은 then 메소드와 catch 메소드로 지정해준다.
function startAsync(age) {
return new Promise((resolve, reject) => {
if (age > 20) resolve(`${age} success`);
else reject(new Error(`${age} is not over 20`));
});
}
setTimeout(() => {
const promise1 = startAsync(25);
promise1
.then((value) => {
console.log(value);
})
.catch((error) => {
console.error(error);
});
const promise2 = startAsync(15);
promise2
.then((value) => {
console.log(value);
})
.catch((error) => {
console.error(error);
});
}, 1000);
async / await
- async 함수는 Promise와 굉장히 밀접한 연관을 갖고 있다. 기존에 작성한 executor로부터 몇 가지 규칙만 적용하면 new Promise(...)를 리턴하는 함수를 쉽게 async 함수로 변환할 수 있다.
- 함수에 async 키워드를 붙이고, new Promise... 부분을 없애고 executor 본문 내용만 남긴다.
- resolve(value); 를 return value; 로 변경한다.
- reject(new Error(..)); 를 throw new Error(...); 로 수정한다.
async function startAsync(age) {
if (age > 20) return `${age} success`;
else throw new Error(`${age} is not over 20`);
}
setTimeout(() => {
const promise1 = startAsync(25);
promise1
.then((value) => {
console.log(value);
})
.catch((error) => {
console.error(error);
});
const promise2 = startAsync(15);
promise2
.then((value) => {
console.log(value);
})
.catch((error) => {
console.error(error);
});
}, 1000);
→ async 함수의 리턴 값은 무조건 Promise 이다!
- await는 Promise가 끝날 때까지 기다리는 함수이고, 반드시 async 함수에서만 사용할 수 있다.
- await를 활용하여 기존 함수 작업의 느낌을 살릴 수 있다.
- await는 Promise가 완료될 때까지 기다리므로, setTimeoutPromise의 executor에서 resolve 함수가 호출될 때까지 기다린다. 그동안 startAsyncJobs()의 진행은 멈춰있다.
- await는 Promise가 resolve한 값을 내놓는다.
function setTimeoutPromise(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), ms);
});
}
async function startAsync(age) {
if (age > 20) return `${age} success`;
else throw new Error(`${age} is not over 20`);
}
async function startAsyncJobs() {
await setTimeoutPromise(1000);
const promise1 = startAsync(25);
try {
const value = await promise1;
console.log(value);
} catch (e) {
console.error(e);
}
const promise2 = startAsync(15);
try {
const value = await promise2;
console.log(value);
} catch (e) {
console.error(e);
}
}
startAsyncJobs();