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

Conversation

sehyun0329
Copy link
Contributor

@sehyun0329 sehyun0329 commented Oct 6, 2024

✅ 학습 내용 요약

React 동작 방식 JSX , state와 props에 대해 학습하였습니다.
JSX가 무엇이며, 상태와 props 전달 및 읽기에 대해 알게되었습니다.

  • 어떤 학습을 했는지 간단하게 요약해주세요.

🤔 고민했던 부분

React에서 불변성을 지켜야 하는 이유가 무엇인지 고민하였고 다른 자료를 찾아보았다. 그 결과,
" 만약 상태를 업데이트할 때 불변성을 유지하지 않으면, 이전 상태와 새로운 상태가 동일한 참조를 가리키게 되어
React가 상태 변화를 감지하지 못할 수 있다. 이는 컴포넌트 최적화를 위해 React.memo와 같은 기능을 사용할 수 없게 된다.
불변성을 유지하지 않으면 React는 상태 변화를 올바르게 감지하지 못해 해당 컴포넌트가 업데이트되어야 하는지 여부를 판단하기 어려워진다.
그 결과, 컴포넌트가 불필요하게 다시 렌더링되어 성능이 저하될 수 있다."

라는 정보를 찾아 고민을 해결할 수 있었다!


또한 "React DOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프하여 XSS 공격을 방지한다." 부분에서 이해가 되지 않았는데,
React는 어떤 값이든 JSX 코드에 직접 작성되지 않으면 그 값을 무시한다.

<div>
  <h1>Hello, {name}!</h1>
</div>

예를 들면 이 JSX 코드에서 {name}은 변수가 들어갈 자리이다.
Hello는 JSX 코드에 직접 작성되었기 때문에 그 값을 무시하지 않고 {name}는 변수가 들어갈 자리니까 JSX 코드에 직접 작성되지 않았으니 그 값을 무시하여 이런 특성으로 인해 공격을 방지할 수 있다.

다시 한 번 정리하자면,
JSX 코드에서 중괄호 안에 전달된 변수나 표현식은 JSX 코드 내부에서 명시적으로 정의되지 않은 값이므로,
React 엔진은 이 값을 이스케이프하여 이를 통해 보안과 안정성 측면에서 중요한 역할을 수행한다.

사용자가 악의적인 코드를 입력해 웹페이지가 이상하게 동작하거나 사용자 정보가 노출될 수 있어서
웹 애플리케이션에서는 사용자가 입력한 내용을 그대로 보여주면 안 되는 경우가 있다.
이를 방지하기 위해 React는 JSX에 삽입된 모든 값을 렌더링하기 전에 이스케이프(escape) 처리를 하는 것이다.

이러한 이스케이프 처리로 인해, 애플리케이션에서 사용자 입력과 같이 명시적으로 작성되지 않은 내용은 그대로 보여지지 않고, 문자열로만 취급된다. 이렇게 함으로써 악의적인 사용자가 제공한 코드가 실행되지 않도록 방지하는 것이다. 이것이 XSS(Cross-Site Scripting) 공격을 방지하는 메커니즘이다.

간단히 말해서, React의 이스케이프 기능은 웹 애플리케이션을 보다 안전하게 만드는 기능으로,
사용자가 입력한 내용을 그대로 표시하지 않고 무효화하여 보안 측면에서 안전성을 확보해준다.

라는 티스토리 글을 참고하여 이해할 수 있었다. 혹시라도 다른 동아리원께서 동일한 부분에서 이해하지 못했다면 내 PR을 보고 고민을 해결했으면 좋겠다는 생각을 하였다!

  • 학습/과제 진행 간 고민한 포인트가 있다면 적어주세요.
  • 고민을 어떻게 생각하고 이를 어떻게 해결하였는지에 대해서 공유해주세요.

🔊 도움이 필요한 부분

  • 도움이 필요한 부분이 없다면 삭제 해도 됩니다.

@sehyun0329
Copy link
Contributor Author

새롭게 fork하느라 1주차의 다른 동아리원 파일이 같이 repository에 추가되어 삭제한 부분은 무시해주시면 감사하겠습니다!

@sehyun0329
Copy link
Contributor Author

sehyun0329 commented Oct 7, 2024

삭제한 1주차 디렉토리들 (다른 동아리원 폴더 및 파일) 다시 만들어서 커밋 했는데 제대로 됐는지 확인 한번만 부탁드려도 될까요??? 죄송합니다ㅠㅠ

Copy link
Contributor

@swgvenghy swgvenghy left a comment

Choose a reason for hiding this comment

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

고생하셨습니다! 전반적으로 저번주보다 정리가 깔끔하게 잘 된 것 같아요!
리뷰 확인해주시고 지금 배우는 주제만 단순히 정리하기보다 저희가 정해드린 주제를 정리할 때 발생하는 의문들과 해당 의문들에 대한 답들을 함께 정리한다면 더욱 깊게 배우며 얻어갈게 더욱 많을 것 같아요! 고생 많으셨습니다!


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


## 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를 사용할 필요가 없습니다. 예를 들어 상태가 간단한 문자열이나 숫자일 때는 기본 자바 스크립트 방법으로 충분합니다.

const [inputValue, setInputValue] = useState('');

const addTodo = () => {
if (inputValue.trim()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

trim을 사용해 공백을 예외처리 한 부분 좋습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

감사합니다!

<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo} <button onClick={() => removeTodo(index)}>Remove</button>
Copy link
Contributor

Choose a reason for hiding this comment

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

todo 내용을 수정, todo를 완료한 표현을 만드려면 어떻게 코드를 수정해야할까? 라는 고민도 함께 해보시는 것도 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

앞으로 더 고민해보고 개발해나가겠습니다!
피드백 감사합니다!

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으로 사용합니다!


// 배열을 직접 수정
items.push(4); // 권장하지 않음
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는 두 상태의 참조가 다르다는 것을 인식하고, 필요한 경우 컴포넌트를 다시 렌더링한다고 합니다!
질문 주셔서 너무 감사합니다!


## 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 전달을 최소화할 수 있다고 합니다!

Comment on lines 21 to 28
<h1>Todo List</h1>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="할 일을 적으세요"
/>
<button onClick={addTodo}>Add</button>
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.

`import React, { useState } from 'react';

// 새로운 TodoInput 컴포넌트로 분리해보았습니다!
const TodoInput = ({ inputValue, setInputValue, addTodo }) => {
return (


<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="할 일을 적으세요"
/>
Add

);
};

// 기존 TodoList 컴포넌트 부분입니다!
const TodoList = () => {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');

const addTodo = () => {
if (inputValue.trim()) {
setTodos([...todos, inputValue]);
setInputValue('');
}
};

const removeTodo = (index) => {
const newTodos = todos.filter((_, i) => i !== index);
setTodos(newTodos);
};

return (


Todo List




    {todos.map((todo, index) => (

  • {todo} <button onClick={() => removeTodo(index)}>Remove

  • ))}


);
};

export default TodoList;
`

이렇게 하면 입력 컴포넌트를 분리함으로써 입력 컴포넌트를 다른 곳에서도 재사용 할 수 있으며, 입력 로직이 변경되더라도 TodoList 컴포넌트는 영향을 받지 않는 장점이 있으며 가독성 또한 좋아진다고 생각합니다! 하나의 컴포넌트에 모든 기능을 포함하는 관점으로 TodoList.jsx를 작성하였는데, 피드백 주신 입력 부분을 새롭게 하나의 컴포넌트로 바꾸어 분리하는 방식이 더 좋은 것 같습니다!
피드백 주셔서 감사합니다!

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에 대해 알 수 있어 좋은 공부가 되었습니다! 감사합니다!


이렇게 새로운 배열인 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로 선언하는 방법이 있습니다!


---

## 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() 메서드를 호출하면 컴포넌트가 강제로 리렌더링 될 수 있습니다!

@sehyun0329
Copy link
Contributor Author

0b34680

TodoList.jsx 컴포넌트들 분리하였습니다!

Copy link
Contributor

@swgvenghy swgvenghy left a comment

Choose a reason for hiding this comment

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

고생하셨습니다! 어제 말씀드렸던 것들 기억해주시고 다음에 참고부탁드립니다! 고생하셨어요!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants