✅ 1. IP 주소를 입력하세요.
https://16-week-lv-1.vercel.app/
✅ 2. GitHub 주소를 입력하세요.
https://github.com/webcreastory/16_WEEK_LV1.git
✅ 3. JSX 문법이란 무엇일까요?
JSX(Javascript XML)은 React에서 사용되는 JS확장문법으로 JS코드 내에 HTML(또는 XML)과 유사한 구조를 작성할 수 있게 해줍니다. 이를 통해 UI를 더욱 직관적으로 작성할 수 있게 하는데 효과적 문법입니다.
✅ 4. 애플리케이션의 상태 값들을 컴포넌트 간 어떤 방식으로 공유하셨나요?
애플리케이션의 상태 값들은 Todo 컴포넌트 내에서 useState를 사용하여 공유하였고, App 컴포넌트에서는 Todo 컴포넌트를 호출하여 렌더링하는 방식으로 공유하였습니다.
✅ 5. 기능 구현을 위해 불변성 유지가 필요한 부분이 있었다면 하나만 설명해 주세요.
clickAddButtonHandler 함수 내에서 setUsers를 호출할 때,
const clickAddButtonHandler = () => {
const newUser = {
id: users.length + 1,
title: title,
text: text,
isDone: false,
};
setUsers([...users, newUser]); // 불변성 유지를 위해 spread 연산자를 사용하여 새로운 배열 생성
setTitle('');
setText('');
};
이 부분에서 setUsers([...users, newUser])를 통해 newUser가 추가된 배열을 생성하여 불변성을 유지하고 있습니다. 이것은 기존의 users 배열을 변경하지 않고 새로운 배열을 생성하여 불변성을 유지하기 위함입니다.
✅ 6. 반복되는 컴포넌트를 파악하고 재사용할 수 있는 컴포넌트로 분리해 보셨나요? 그렇다면 어떠한 이점이 있었나요?
User 컴포넌트가 반복되는 패턴이 있으며, 이를 재사용 가능한 컴포넌트로 분리하여 코드를 개선하기 위해 User 컴포넌트를 Todo 컴포넌트로부터 분리함으로써, 코드의 가독성을 높일 수 있습니다.
✅ App.js
import React from 'react'; // React 라이브러리를 사용하기 위해서는 항상 React를 임포트해야 함
import './App.css'; // App.css 파일을 임포트하고 있음
import Todo from './components/Todo'; // Todo컴포넌트를 components폴더 안에 있는 Todo.jsx파일로부터 임포트하고 있음
// App이라는 함수형 컴포넌트 : React 애플리케이션의 진입점(entry point)
// 이 컴포넌트는 <Todo></Todo>라는 JSX를 반환 (Todo 컴포넌트를 렌더링하는 역할을 함)
function App() {
return <Todo></Todo>;
}
// App 컴포넌트를 모듈의 기본으로 내보냄
export default App;
// App 컴포넌트는 Todo 컴포넌트를 렌더링하고,
// 애플리케이션의 최상위 레벨에 위치하여
// 각 컴포넌트들을 조합하고 화면에 보여주는 역할을 함
✅ components
✅ Todo.jsx
// React는 React애플리케이션을 구성하는 핵심 라이브러리
// React라이브러리에서 React와 useState를 가져옴.
// useState는 React컴포넌트에서 상태관리를 위한 Hook 중 하나
import React, { useState } from 'react';
// 현재 디렉토리에서 ./User경로로 지정된 파일에서 User컴포넌트를 가져옴
// 다른 파일에 정의된 User컴포넌트를 현재 파일에서 사용하겠다는 의미
import User from './User';
// 메인 컴퍼넌트
// React 함수형 컴포넌트
// 함수형 컴포넌트 Todo를 선언(화살표 함수 문법)
const Todo = () => {
// 초기 상태 설정
// useState 훅(Hook)을 사용하여 컴포넌트의 상태를 초기화
// useState는 배열 형태의 반환값을 가지며
//--- 첫번째 원소 users(상태 변수의 이름)는 상태값 자체, 두번째 원소 setUsers는 해당 상태를 업데이트하는 함수
const [users, setUsers] = useState([
// 초기 상태로 지정된 값은 배열
// 각 원소는 하나의 Todo를 나타내는 객체
// 객체에는 id(고유 식별자), title, text, isDine 속성
{ id: 1, title: '[과제] React Lv.1', text: 'My Todo List 제출', isDone: false },
{ id: 2, title: '[강의] 리액트 입문주차', text: '2회독_개발 블로그 정리', isDone: true },
]); // = 이 코드는 초기 화면에 렌더링될 때 users 상태가 초기화되고 해당 상태는 title과 text라는 2개의 Todo 객체를 가지고 있음
// 이후에 이 상태를 업데이트하거나 활용하여 React 컴포넌트를 동적으로 변경할 수 있음
// React 함수형 컴포넌트에서 useState 훅을 사용하여 2개의 상태 변수를 선언
// 첫번째 상태 변수인 title을 선언하고 초기값을 빈 문자열로 설정(title은 현재 상태의 값, setTitle 함수를 사용해 이 상태를 업데이트)
// 두번째 상태 변수인 text을 선언하고 초기값을 빈 문자열로 설정(text는 현재 상태의 값, setText 함수를 사용해 이 상태를 업데이트)
const [title, setTitle] = useState('');
const [text, setText] = useState('');
// = 이렇게 선언된 상태 변수들은 주로 사용자의 입력을 받거나, 컴포넌트 내에서의 상태를 관리하는 데 사용
// 제목 입력값 변경 핸들러
// React 함수형 컴포넌트에서 사용되는 event 핸들러 함수
// titleChangeHandler라는 이름의 '함수형 변수'를 선언
// 주로 입력 필드에서 발생하는 event(일반적으로 입력 내용이 변경될 때 발생하는 'onChange' event)를 처리
const titleChangeHandler = (event) => { // 화살표 함수 문법을 사용하여 이벤트 핸들러 함수 정의(이벤트(event) 객체를 받아들이는 매개변수)
setTitle(event.target.value); // setTitle 함수 호출(React 컴포넌트에서 title 상태 업데이트) ->
// event.target.value 값을 setTitle 함수에 전달하여 컴포넌트의 title 상태 업데이트
}; // event.target은 이벤트가 발생한 HTML 요소(주로 입력 필드)/.value는 해당 요소의 현재 값, 즉 사용자가 입력한 내용을 나타냄
// = 주로 사용자가 입력 필드에 텍스트를 입력할 때마다 호출되어, 입력된 텍스트를 컴포넌트의 title 상태로 업데이트하는 역할
// = 입력된 값을 상태로 관리하고, 필요에 따라 화면을 다시 렌더링하여 반영
// 내용 입력값 변경 핸들러
//textChangeHandler라는 이름의 함수형 변수를 선언
// 주로 입력 필드에서 발생하는 이벤트(일반적으로 입력 내용이 변경될 때 발생하는 'onChange' 이벤트) 처리
const textChangeHandler = (event) => { // 화살표 함수 문법을 사용하여 이벤트 핸들러 함수 정의
// 매개변수 event는 이벤트 객체를 받아들이는 매개변수
setText(event.target.value); // event.target.value는 이벤트가 발생한 HTML 요소(주로 입력 필드)의 현재 값,
// 즉 사용자가 입력한 내용을 나타냄(이 값을 setText 함수에 전달하여 컴포넌트의 text 상태를 업데이트)
}; // 사용자가 입력 필드에 텍스트를 입력할 때마다 호출되어, 입력된 텍스트를 컴포넌트의 text 상태로 업데이트하는 역할
// 버튼 컴포넌트(함수형 컴포넌트)
// Button이라는 이름의 함수형 컴포넌트 선언
// 이 컴포넌트는 주로 버튼 역할을 하며, 두 개의 속성(props)을 받아들임
// clickAddButtonHandler: 이는 버튼이 클릭되었을 때 실행될 이벤트 핸들러 함수
// children: 이는 버튼 내에 포함될 내용(일반적으로 텍스트 또는 다른 React 엘리먼트)
const Button = ({ clickAddButtonHandler, children }) => {
// 이 부분은 컴포넌트의 렌더링을 정의
// <button> HTML 엘리먼트 반환
// onClick={clickAddButtonHandler}는 버튼이 클릭되었을 때 실행될 이벤트 핸들러를 정의
// clickAddButtonHandler로 전달된 함수가 클릭 이벤트에 바인딩되어 해당 함수가 실행됨
// {children}: 이는 버튼 내에 포함될 내용을 나타냄(버튼 내의 텍스트로 표시됨)
return <button onClick={clickAddButtonHandler}>{children}</button>;
}; // = Button 컴포넌트를 정의하여, 버튼을 렌더링하고 클릭 이벤트에 대한 핸들러를 받아 처리할 수 있는 컴포넌트
// <추가> 버튼 클릭시 카드 추가하기
// clickAddButtonHandler 함수가 호출될 때마다, 새로운 사용자 정보를 만듦
const clickAddButtonHandler = () => {
const newUser = { // newUser 객체를 생성하는데, 이 객체에는 다음과 같은 속성 포함(id, title, text, isDone)
id: users.length + 1, // users 배열의 길이에 1을 더한 값으로 설정
title: title, // title 변수에서 가져온 값으로 설정
text: text, // text 변수에서 가져온 값으로 설정
isDone: false, // 새로운 사용자의 상태를 나타냄(아직 완료되지 않았다는 것을 의미)
};
// setUsers 함수를 호출하여 users 배열 업데이트
setUsers([...users, newUser]);
// 기존 users 배열과 새로 생성된 newUser 객체를 합친 새로운 배열을 생성하여 업데이트
// <추가> 버튼 클릭 후 입력값 초기화
// 입력 필드의 값을 변경한 후에 해당 값을 초기화
setTitle('');
setText('');
};
// Working 섹션에서 <삭제> 버튼 클릭 핸들러
// clickRemoveButtonHandler 함수는 id라는 매개변수를 받음
// 사용자가 지정한 id를 가진 항목을 삭제하기 위한 것
const clickRemoveButtonHandler = (id) => {
// filter 메서드를 사용하여 users 배열에서 조건을 만족하는 요소들만 새로운 배열인 newUsers에 포함
// filter 함수는 각각의 user에 대해 주어진 조건을 확인하고,
// user.id가 함수에 전달된 id와 일치하지 않는 요소들만 선택하여 새로운 배열을 생성
// id와 일치하지 않는 사용자만을 남기고 필터링
const newUsers = users.filter((user) => user.id !== id);
// setUsers 함수를 호출하여 상태(state)를 업데이트
// newUsers 배열은 이전 users 배열에서 특정 id를 가진 사용자를 제외한 새로운 배열
// 새로운 사용자 목록으로 설정하여 이전 목록에서 해당 ID를 가진 사용자를 삭제
setUsers(newUsers);
};
// <완료> 또는 <취소> 버튼 클릭시 상태 변경
// toggleStatusFunction 함수는 id라는 매개변수를 받음
const toggleStatusFunction = (id) => {
// map 함수를 사용하여 users 배열의 각 요소를 새로운 배열인 updatedUsers로 변환
// map() 함수는 배열의 각 요소에 대해 주어진 함수를 호출하고, 그 함수가 반환하는 결과를 모아서 새로운 배열을 생성
// ----- 배열을 순회하면서 각 요소에 동일한 작업을 적용하여 새로운 배열을 만들 때 유용
const updatedUsers = users.map((user) => {
// 만약 user.id가 함수에 전달된 id와 일치한다면, 해당 사용자의 isDone 속성을 반전시켜서 변경
if (user.id === id) {
// 객체 전개 연산자(...)를 사용하여 객체를 복사하고, 해당 객체의 isDone 속성을 토글(반전)시킴
// 반전 연산자 !를 사용하여 user.isDone의 값을 뒤집고, 해당 값을 가지고 새로운 객체를 생성하여 반환
// 그렇지 않은 경우에는 기존의 사용자 정보를 그대로 반환
return { ...user, isDone: !user.isDone };
}
return user;
}); //setUsers 함수를 호출하여 상태(state)를 업데이트
setUsers(updatedUsers);
// updatedUsers 배열은 이전 users 배열을 기반으로
// --- 특정 id를 가진 사용자의 isDone 값을 토글(반전)시킨 새로운 배열
};
// Done 섹션에서 <삭제> 버튼 클릭 핸들러
// clickRemoveDoneButtonHandler 함수는 id라는 매개변수를 받음
// 특정 조건을 충족하는 사용자(isDone이 true인 사용자)를 제외하고 새로운 배열을 만듦
const clickRemoveDoneButtonHandler = (id) => {
// filter 함수를 사용하여 users 배열에서 조건을 만족하는 요소들만 새로운 배열인 newUsers에 포함시킴
const newUsers = users.filter((user) => user.id !== id);
// newUsers 배열은 이전 users 배열에서 특정 id를 가진 사용자를 제외한 새로운 배열
// = id에 해당하는 사용자를 제거하고, 해당 사용자가 완료된 작업을 나타내는 isDone이 true인 경우에만 동작
setUsers(newUsers);
};
// JSX(JavaScript XML, React에서 UI를 작성하기 위해 사용되는 JS 확장 문법)로 작성된 코드
// 1. Todo List 구성 요소:
// clickRemoveDoneButtonHandler, clickAddButtonHandler, titleChangeHandler, textChangeHandler,
// toggleStatusFunction 함수들과 함께 <Button>과 <User> 컴포넌트를 사용하여 Todo List를 구성
// 2. 화면 레이아웃 구성:
// home-background, home-container, header, input-box, Working-body 등의 CSS 클래스를 사용하여 UI 스타일링
// 헤더에는 My Todo List와 React라는 두 개의 텍스트 구성
// 3. 두 부분으로 나누어진 Todo 리스트:
// Working 부분은 isDone이 false인 항목들을 보여주고 있고,
// Done 부분은 isDone이 true인 항목들을 보여줌
// 두 부분에서 각각 filter 함수를 사용하여 users 배열을 필터링하고, 해당하는 부분에 맞는 항목들만을 보여줌
// map 함수를 사용하여 각각의 Todo 항목을 User컴포넌트로 변환하고, 해당 컴포넌트들을 UI에 렌더링 함
return (
<div className="home-background">
<div className="home-container">
<div className="header">
<span>My Todo List</span>
<span>React</span>
</div>
<div className="input-box">
제목
<input value={title} onChange={titleChangeHandler} />
내용
<input value={text} onChange={textChangeHandler} />
<Button clickAddButtonHandler={clickAddButtonHandler}>추가하기</Button>
</div>
<h1>🔥 Working</h1>
<div className="Working-body">
{users
.filter((item) => !item.isDone)
.map(function (item) {
return (
<User
key={item.id}
item={item}
removefunction={clickRemoveButtonHandler}
toggleStatusFunction={toggleStatusFunction}
/>
);
})}
</div>
<h1>👍 Done</h1>
<div className="Working-body">
{users
.filter((item) => item.isDone)
.map(function (item) {
return (
<User
key={item.id}
item={item}
removefunction={clickRemoveDoneButtonHandler}
toggleStatusFunction={toggleStatusFunction}
/>
);
})}
</div>
</div>
</div>
);
};
export default Todo;
// Todo라는 컴포넌트를 내보내고 다른 파일에서 가져와서 사용
✅ User.jsx
// React 라이브러리를 현재 파일에서 사용하겠다고 선언
import React from 'react';
// User라는 함수형 컴포넌트
// ES6의 비구조화 할당을 사용하여 컴포넌트의 props를 바로 받아옴
// props = item, removefunction, toggleStatusFunction
const User = ({ item, removefunction, toggleStatusFunction }) => {
return (
// React에서 리스트를 렌더링할 때 각 요소에 고유한 key를 지정해야 함
// item.id를 키로 사용
// item.isDone이 true인 경우에만 done 클래스가 추가됨(완료된 항목은 스타일링을 위해 done 클래스를 받음)
// item 객체에 있는 title과 text 값을 출력
<div key={item.id} className={`todo-container ${item.isDone ? 'done' : ''}`}>
{item.title}
<br />
{item.text}
<br />
<div className="button-container">
<button onClick={() => removefunction(item.id)}>삭제하기</button>
<button onClick={() => toggleStatusFunction(item.id)}>{item.isDone ? '취소' : '완료'}</button>
</div>
</div> // 버튼을 클릭하면 removefunction이 호출되고, 해당 item의 id가 전달 -> 이를 통해 해당 아이템이 삭제되는 함수를 실행
); // 버튼 텍스트를 item.isDone의 상태에 따라 다르게 표시
// item.isDone이 true라면 '취소'라는 텍스트가 보이며, 클릭 시 toggleStatusFunction이 호출
}; // item.isDone이 false라면 '완료'라는 텍스트가 보이고, 클릭 시 toggleStatusFunction이 호출
export default User;
// User 컴포넌트는 각 Todo 항목을 렌더링하고, 해당 항목의 삭제와 상태 변경을 담당하는 버튼을 보여줌
// 설정된 item prop으로부터 해당 항목의 정보를 받아와 UI로 표시하고,
// removefunction과 toggleStatusFunction을 호출하여 해당 항목의 삭제 및 상태 변경을 처리
✅ User.css
.home-background {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
/* 배경 이미지가 컨텐츠 위에 나타나도록 설정 */
background-image: linear-gradient(45deg,
rgb(51 43 43 / 75%),
rgb(20 19 20 / 61%)), url("https://miro.medium.com/v2/resize:fit:1400/1*QDQvlCg420lzRElCK4AYhw.png");
background-position: center;
background-size: cover;
background-repeat: no-repeat;
}
.home-container {
width: 1200px;
margin: 0px auto 0px auto;
}
.header {
height: 50px;
width: 1100px;
padding: 10px;
margin-bottom: 10px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
font-size: 50px;
font-weight: 700;
color: rgb(18, 78, 89);
}
.input-box {
background-color: rgba(44, 40, 40, 0.921);
border-radius: 6px;
height: 100px;
width: 1100px;
padding-left: 30px;
padding-right: 30px;
color: white;
font-size: 25px;
font-weight: 800;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.input-box>input {
height: 40px;
width: 280px;
margin-right: auto;
padding-left: 10px;
border-radius: 7px;
border: none;
font-size: 18px;
font-weight: 600;
}
.input-box>Button {
width: 180px;
height: 45;
padding: 10px;
background-color: rgb(71, 163, 182);
border: none;
border-radius: 5px;
color: white;
font-size: 20px;
font-weight: 800;
}
.input-box>Button:hover {
width: 180px;
height: 45;
padding: 10px;
border: none;
border-radius: 5px;
font-size: 22px;
font-weight: 900;
color: white;
background-color: red;
}
h1 {
margin-right: 1000px;
margin-bottom: 15px;
font-size: 30px;
font-weight: 800;
color: white;
}
.Working-body {
display: flex;
flex-wrap: wrap;
gap: 12px;
padding-left: 30px;
}
.todo-container {
width: 350px;
height: 200px;
border: 5px solid white;
border-radius: 10px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 20px;
font-weight: 800;
color: white;
}
.button-container>Button {
width: 100px;
height: 40;
padding: 10px;
margin: 10px;
background-color: red;
border: none;
border-radius: 5px;
color: white;
font-size: 15px;
font-weight: 700;
}
.button-container>Button:hover {
width: 100px;
height: 40;
padding: 10px;
margin: 10px;
background-color: black;
border: none;
border-radius: 5px;
color: white;
font-size: 16px;
font-weight: 700;
}
'Javascript' 카테고리의 다른 글
DOM-API 실습 (1) | 2023.12.19 |
---|---|
DOM:Document object Model 기본 개념 (0) | 2023.12.19 |
콜백함수 제너레이터(Generator) (0) | 2023.12.19 |
비동기 작업의 동기적 표현 - Promise (0) | 2023.12.19 |
콜백함수_promise (1) | 2023.12.18 |