Form 개발
React를 이용해 사용자로부터 데이터를 입력받아 처리하기 위한 관문인 Form
이번 실습에서는 State와 이벤트를 활용해 개발을 진행
구현할 Form의 형태
- 컴포넌트 형태로 개발
- Form 컴포넌트 내부에서 State를 이용해 사용자의 입력을 저장/관리
- Form의 Submit 이벤트가 발생되면 부모 컴포넌트로 그 데이터를 전달
import React, { useState, useCallback } from "react";
const InsertForm = ({ onInsert }) => {
const [inputValue, setInputValue] = useState("");
const handleSubmit = useCallback((event) => {
// 기본적인 HTML 동작으로 인해 페이지가 새로고침 되는 것을 방지
event.preventDefault();
// props로 넘어온 onInsert가 정상적인 함수인 지 확인하여 에러 방지
if(typeof onInsert === "function" && inputValue) {
onInsert(inputValue);
}
// state 초기화
setInputValue("");
},[onInsert, inputValue])
return (
<form onSubmit={handleSubmit}>
<input value={inputValue} onChange={(event) => {
setInputValue(event.target.value);
}} />
<button type="submit">등록</button>
</form>
)
}
export default InsertForm;
List 표현
Form으로부터 전달받은 값들을 리스트에 저장 후, 리스트의 값을 Array 메소드 이용하여 순차적으로 화면에 출력
구현할 List의 형태
- Form으로부터 전달받은 값을 todoList array에 push하는 로직
//src/App.js
import React, { useState } from 'react';
import InsertForm from "./components/InsertForm";
import ListView from "./components/ListView";
function App() {
const [todoList, setTodoList] = useState([]);
const handleInsert = (value) => {
setTodoList((current) => {
const newList = [...current];
newList.push({
key: new Date().getTime(), // JSX에서 Array의 값을 표현할 때 각 요소를 구분하기 위한 값
value: value, // onInsert로부터 전달받은 값,
isCompleted: false, // 완료 처리를 위한 flag
});
return newList;
})
}
const handleComplete = (index) => {
setTodoList((current) => {
const newList = [...current];
newList[index].isCompleted = true;
return newList;
})
}
const handleRemove = (index) => {
setTodoList((current) => {
const newList = [...current];
newList.splice(index, 1);
return newList;
})
}
return (
<div className="App">
<ListView todoList={todoList} onComplete={handleComplete} onRemove={handleRemove} />
<InsertForm onInsert={handleInsert} />
</div>
);
}
export default App;
- todoList와 핸들링함수를 props로 전달받아 화면에 출력하는 ListView 컴포넌트
// src/component/ListView.js
import React from "react";
const ListView = ({todoList, onComplete, onRemove}) => {
return (
<div>
<ol>
{todoList.map((item, index) => {
return (
<li key={item.key}>
<span>{item.value}</span>
<button type="button" onClick={() => {
if(typeof onComplete === "function") {
onComplete(index);
}
}}>완료</button>
<button type="button" onClick={() => {
if(typeof onRemove === "function") {
onRemove(index);
}
}}>삭제</button>
</li>
);
})}
</ol>
</div>
)
}
export default ListView;
CSS 꾸미기
1. CSS 불러오기
별도의 CSS 파일을 작성 후 프로젝트에 적용하고 싶은 경우 import해서 스타일을 적용한다.
import "./App.css";
2. jsx 내에서 inline style로 적용하기
스타일은 반드시 object로 적는다. {{ }}
(jsx에서 자바스크립트 표현을 사용하겠다는 의미의 괄호 + object라는 의미의 괄호)
* 주의) Property name은 camel case로 적는다.
return (
<form
onSubmit={handleSubmit}
style={{
backgroundColor: '#ffffff',
borderRadius: '16px',
marginBottom: '16px',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<input
value={inputValue}
onChange={event => {
setInputValue(event.target.value);
}}
style={{
flex: 1,
border: 'none',
color: '#000000',
padding: '6px, 12px',
backgroundColor: 'transparent',
}}
/>
<button
type="submit"
style={{
border: 'none',
borderRadius: 16,
backgroundColor: '#3ab6bc',
color: '#ffffff',
cursor: 'pointer',
padding: '8px 16px',
}}
>
등록
</button>
</form>
);
jsx에서 스타일은 반드시 camel case로 선언해야 함!!
background-color 대신 backgroundColor
border-radius 대신 borderRadius
부가 기능 구현
- 완료버튼 클릭시 이펙트(애니메이션) 추가하기
.listview ol li span {
...
position: relative;
}
.listview ol li span::after {
content: "";
position: absolute;
left: 0;
top: 50%;
transition: width 0.2s ease-in-out;
width: 0%;
height: 3px;
background-color: #524FA1;
}
.listview ol li.completed span::after {
width: 100%;
}
// 제거
.listview ol li.completed span
- todolist 개수를 제한하기
list가 10개 이상이면 제한하는 기능
const isLimitReached = useMemo(() => {
return todoList.length >= 10;
}, [todoList]);
return (
<div className="App">
<ListView
todoList={todoList}
onComplete={handleComplete}
onRemove={handleRemove}
/>
{isLimitReached && (
<div
style={{
padding: '8px 16px',
border: '1px solid #FA466A',
backgroundColor: '#feecf0',
color: '#FA466A',
marginBottom: 16,
}}
>
※ 할일 목록이 너무 많습니다.
</div>
)}
<InsertForm onInsert={handleInsert} disabled={isLimitReached} />
</div>
);
'프론트엔드 > react.js' 카테고리의 다른 글
[React.js] Hooks (0) | 2022.11.21 |
---|---|
[React.js] 이벤트 처리 (0) | 2022.11.15 |
[React.js] State (0) | 2022.11.14 |
[React.js] Prop (0) | 2022.11.14 |
[React.js] JSX와 컴포넌트 (0) | 2022.11.14 |