Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2주차] 김세현 학습 PR 제출합니다. #14

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
162 changes: 162 additions & 0 deletions week02/김세현/[2주차] 김세현.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
## JSX란? (JavaScript eXtension)

JSX는 JavaScript를 확장한 문법이며, JavaScript의 모든 기능이 포함되어 있다.

React에서 JSX 사용이 필수가 아니지만, 대부분 JavaScript 코드 안에서 UI 관련 작업을 할 때 시작적으로 더 도움이 된다고 생각한다. 또한 React가 더욱 도움이 되는 에러 및 경고 메시지를 표시할 수 있게 해준다.

## JSX도 표현식이다.

```
const name = 'Josh Perez';

const element = <h1>Hello, {name}</h1>;
```

name이라는 변수를 선언한 후 중괄호로 감싸 JSX에 사용하였는데, JSX의 중괄호 ({}) 안에는 유효한 모든 JavaScript 표현식을 넣을 수 있다.

컴파일이 끝나면, JSX 표현식이 정규 JavaScript 함수 호출이 되고 JavaScript 객체로 인식된다.

## JSX 속성 정의

어트리뷰트에 따옴표를 사용해 문자열 리터럴을 정의할 수 있으며, 중괄호를 사용해 JavaScript 표현식을 삽입할 수 있다.

```
const element = <a href="https://www.reactjs.org">link</a>;
const element = <img src={user.avatarUrl} />;
```

JSX에서는 HTML 어트리뷰트 이름 대신 camelCase 프로퍼티 명명 규칙을 사용한다. 예를 들어, `class`는 `className`으로 사용된다.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

class대신 className으로 사용해야하는 이유는 무엇인가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어라 위의 방금 내용 Resolve conversation을 잘못 눌러버렸네요 ㅠㅠ
아무튼 JSX에서 class 대신 className을 사용하는 이유는 예약어 충돌 때문입니다!
class는 ES6(ECMAScript 2015)에서 도입된 자바 스크립트의 예약어로, 클래스 정의에 사용하는데, JSX는 자바스크립트의 문법을 기반으로 하기 때문에, class를 속성 이름으로 사용할 경우 문법적으로 문제가 발생할 수 있기에 className으로 사용합니다!


## JSX로 자식 정의

```
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
```

JSX 태그는 자식을 포함할 수 있으며, 태그가 비어있다면 XML 처럼 />로 닫아야 한다.

## JSX는 주입 공격을 방지한다.

JSX에 사용자 입력을 삽입하는 것은 안전하다. React DOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프하여 XSS 공격을 방지한다.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XSS공격은 어떤 공격일까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XSS(교차 사이트 스크립팅) 공격은 악의적인 사용자가 웹 페이지에 스크립트 코드를 삽입하여 다른 사용자의 브라우저에서 실행시키는 공격입니다. 이 공격을 통해 공격자는 사용자의 세션 정보를 탈취하거나, 웹 페이지의 내용을 변조하거나, 악성 소프트웨어를 배포할 수 있습니다!


```
const title = response.potentiallyMaliciousInput;
const element = <h1>{title}</h1>; // 안전함
```

---

## React에서 객체 업데이트 방법
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리액트에서 컴포넌트가 재렌더링 되는 때는 어떤 경우일까요 ??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

먼저 컴포넌트의 Props나 State가 변경되면, React는 해당 컴포넌트를 리렌더링합니다. 이 때, 부모 컴포넌트의 리렌더링도 자식 컴포넌트의 리렌더링을 유발할 수 있다고 합니다!
또 Context를 활용하는 경우, Context의 값이 변경되면 해당 값을 사용하는 모든컴포넌트가 리렌더링 되며, forceUpdate() 메서드를 호출하면 컴포넌트가 강제로 리렌더링 될 수 있습니다!


상태를 **읽기 전용**으로 다루어야 하며, 기존 객체를 변경하는 대신 새로운 객체를 생성해야 한다.

React는 state 설정 함수 (setState 같이)가 없으면 객체가 변경되었는지 알 수 없다. 따라서 React는 아무것도 하지 않는다.

그렇기에 렌더링 시에 접근하려는 state 값은 **읽기 전용**처럼 다루어야 한다.

## 불변성이란?

불변성은 객체의 상태를 직접 변경하지 않고, 새로운 객체를 생성하여 업데이트 하는 원칙이다.

React에서 배열 상태 업데이트 할 때, 불변성을 지키지 않은 경우이다.

```
const [items, setItems] = useState([1, 2, 3]);

// 배열을 직접 수정
items.push(4); // 권장하지 않음
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

왜 권장하지 않는지 closer에 대해 학습하고, closeruseState 내부에서 어떻게 활용되고 있는지 공부해보면 좋을 것 같습니다~

Copy link
Contributor Author

@sehyun0329 sehyun0329 Oct 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

배열을 직접 수정하면 React가 상태 변경 수정을 감지하지 못하게 되어 UI 업데이트가 발생하지 않아 버그를 초래할 수 있거나 변경을 감지하지 못해 불필요한 렌더링이 발생할 수 있다고 합니다!
closure는 함수와 그 함수가 선언된 어휘적 환경(Lexical Environment)의 조합을 의미하며 함수가 그 당시에 선언 되었을때의 모든 정보(변수, 환경 내의 정보들)을 기억하고, 호출되어 처리가 끝나고 소멸 된 이후에도 그 당시의 모든 정보를 기억하며 접근할 수 있음을 의미한다고 합니다.
이를 통해 상태를 유지하거나 특정 값을 캡슐화 할 수 있습니다.
`import React, { useState } from 'react';

const Counter = () => {
const [count, setCount] = useState(0);

const increment = () => {
    setCount(count + 1);
};

return (
    <div>
        <p>{count}</p>
        <button onClick={increment}>Increment</button>
    </div>
);

};

export default Counter;`

위의 예시 코드에서 increment 함수에서 현재 count의 값을 클로저로 캡처하여 사용할 수 있습니다.
(출처: https://adjh54.tistory.com/64)

Closure에 대해 알 수 있어 좋은 공부가 되었습니다! 감사합니다!

setItems(items); // React는 변경을 감지하지 못함
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

왜 React에서는 해당 부분 변경을 감지하지 못할까요?
추가적으로 React에서 불변성을 유지하기위해 사용되는 참조비교에 대해 알아보면 좋을 것 같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀해주신 참조 비교를 찾아본 내용입니다!
React는 상태 업데이트를 위해 이전 상태와 새로운 상태의 참조를 비교합니다. 직접 배열을 수정하면, 원래의 배열 참조는 그대로 유지되고, React는 상태가 변경되지 않았다고 판단한다고 합니다!
해당 부분 변경을 감지하지 못하는 방법으로 추가적으로 조사해 본 것이 불변성 원칙 때문이라고 합니다.
React는 상태를 직접 수정하는 대신 새로운 객체나 배열을 생성하여 상태를 업데이트해야 합니다. 이렇게 함으로써 React는 두 상태의 참조가 다르다는 것을 인식하고, 필요한 경우 컴포넌트를 다시 렌더링한다고 합니다!
질문 주셔서 너무 감사합니다!

```

React에서 배열 상태를 업데이트 할 때, 불변성을 지킨 경우이다.

```
const [items, setItems] = useState([1, 2, 3]);

// 새로운 배열을 생성
const newItems = [...items, 4];
setItems(newItems); // React는 변경을 감지하고 리렌더링

```

이렇게 새로운 배열인 newItems를 생성하여 setItems로 상태를 업데이트를 했다.

불변성을 유지하는 것은 코드의 안정성, 예측 가능성, 디버깅 용이성을 높이는 데 중요한 역할을 하므로 반드시 불변성을 염두에 두고 코드를 작성하는 것이 좋다.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

불변성을 유지하는 방법으로는 어떤 것이 있을까요 ??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

찾아본 바로는
오늘 ('...todos') 연산자 처럼 spread 연산자('...')를 사용해서 불변성을 지키면서 값을 업데이트할 수 있습니다!
spread 연산자를 사용할 경우 기존에 선언한 값은 그대로 두고 값을 복사하여 사용하는 것이기에 불변성이 유지됩니다.
또 변수를 선언할 때는 재할당이 되지 않도록 const로 선언하는 방법이 있습니다!


## 객체 전개 구문

객체의 전개 구문을 사용하면 기존 객체의 프로퍼티를 쉽게 복사할 수 있다.

```
setPerson({

...person, // 이전 필드를 복사

firstName: e.target.value // 새로운 부분은 덮어쓰기

});
```

위의 코드를 통해 단 한 개의 필드만 수정하고, 나머지 모든 필드는 이전 값을 유지하고 싶을 때 유용한 방법이다.

* 주의: ...전개 문법은 얕다. 빠르지만, 중첩된 프로퍼티를 업데이트하고 싶다면 한 번 이상 사용해야 한다.

## Immer 사용

Immer를 사용하면 상태 업데이트를 간결하게 관리할 수 있다. Immer는 내부적으로 변경 사항을 기록하여 새로운 객체를 생성한다.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Immer라는 라이브러리를 언급하셨는데 해당 부분에서 라이브러리 언급을 하셨다면 간단하게 사용하는 이유에 대해서도 설명하면 좋을 것 같아요. 가령 Immer 사용이 필요없는 상황도 있을텐데 어떤 경우에 해당 라이브러리를 사용하는지, 이 라이브러리를 사용하면 기존에 비해 어떻게 좋아지는지 등을 파악해야한다고 생각합니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Immer는 상태 업데이트를 간결하게 관리할 수 있도록 도와주는 라이브러리인데요, 주로 불변성 유지 (상태를 직접 수정하지 않고, 변경 사항을 기록하여 새로운 객체를 생성하여), 가독성 향상 (스프레드 연산자 사용 같은 기존의 불변성 유지 방법보다 코드를 더 간결하게 작성할 수 있다), 복잡한 상태 관리 (중첩된 객체나 배열을 다룰 때 더 쉽게 처리 가능) 같은 이유로 사용된다고 합니다.
또한 단순한 상태 업데이트나 불변성을 유지할 필요가 없는 경우에는Immer를 사용할 필요가 없습니다. 예를 들어 상태가 간단한 문자열이나 숫자일 때는 기본 자바 스크립트 방법으로 충분합니다.


---

## 1. Props 전달하기

부모 컴포넌트는 JSX 태그에 props를 추가하여 자식 컴포넌트에 정보를 전달한다.

예를 들어

```
...
<Avatar person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }} size={100} />
```

처럼 person(객체)와 size (숫자)를 전달할 수 있다.

## 2. props 읽기

자식 컴포넌트에서 구조 분해 할당을 통해 전달된 props를 읽는다.

```
function Avatar({ person, size }) {

// person과 size는 이곳에서 사용가능합니다.

}
```

function Avatar 바로 뒤의 person, size 등을 쉼표로 구분하여 읽을 수 있다.

이렇게 하면 Avatar 코드 내에서 변수를 사용하는 것처럼 사용할 수 있다.

## 3. 기본값 지정하기

props에 기본값을 설정할 수 있다. 예를 들어, `size = 100`과 같이 하면 size가 전달되지 않았을 때 기본값으로 100이 사용된다.

## 4.JSX로 자식 전달하기

JSX 태그 내에 자식 요소를 중첩하면, 부모 컴포넌트는 이 자식을 `children` prop으로 받을 수 있다.

```
<Card>

<Avatar />

</Card>
```

## 5. 시간에 따른 props 변하는 방식

props는 컴포넌트가 렌더링될 때마다 새로운 값을 받을 수 있으며, 이는 변경할 수 없는 불변성을 가진다. 상태가 필요한 경우 state를 사용해야 한다.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Props를 사용하는 이유와 장단점, 자식 컴포넌트가 많아졌을때 props에 대한 처리방법에 대해 생각해보면 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Props는 데이터 전달 (부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달), 재사용성 (컴포넌트를 재사용 할 수 있으며, 다양한 데이터를 받아 동일한 컴포넌트를 여러 번 사용할 수 있다), 불변성 유지 (props는 불변성을 가지므로, 자식컴포넌트 내에서 변경되지 않고 안정적인 데이터 전달을 보장)의 이유로 사용합니다!
먼저 장점으로는

  1. 명확한 데이터 흐름: 부모에서 자식으로 데이터가 흐르므로, 컴포넌트 간의 관계가 명확해집니다!
  2. 테스트 용이: Props를 통해 전달된 데이터로컴포넌트를 테스트할 수 있어 테스트 작성이 쉬워진다고 합니다!
  3. 상태 관리 분리: 상태가 필요한 경우에는 state를 사용하고, 단순히 데이터를 전달할 때는 props를 사용하여 역할을 분리할 수 있다고 합니다!

단점으로는

  1. 상태 관리 복잡성: Props가 깊게 전달될 경우, 중간 컴포넌트에서도 props를 계속 전달해야 하므로 코드가 복잡해질 수 있습니다.
  2. 불변성 제한: 자식 컴포넌트에서 props를 수정할 수 없기 때문에, 상태 관리가 필요한 경우 별도의 state를 관리해야한다고 합니다.

자식 컴포넌트가 많아졌을 때,

  1. Context API 사용: React의 Context API를 사용하여 여러 컴포넌트에 걸쳐 데이터를 공유할 수 있습니다. 이를 통해 props를 일일이 전달하지 않고도 필요한 곳에서 데이터를 사용할 수 있다고 합니다.
  2. 상태 관리 라이브러리: Redux, MobX와 같은 상태 관리 라이브러리를 사용하여 전역 상태를 관리함으로써, props 전달을 최소화할 수 있다고 합니다!

24 changes: 24 additions & 0 deletions week02/김세현/todo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
8 changes: 8 additions & 0 deletions week02/김세현/todo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# React + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
38 changes: 38 additions & 0 deletions week02/김세현/todo/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
settings: { react: { version: '18.3' } },
plugins: {
react,
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
...reactHooks.configs.recommended.rules,
'react/jsx-no-target-blank': 'off',
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
13 changes: 13 additions & 0 deletions week02/김세현/todo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Loading