스터디/프론트 cs 스터디(23.08-23.11)

# React 관련 지식 - 3

minseokiim 2023. 9. 12. 03:45

- React에서 State의 불변성은 어떻게 유지할 수 있나요? (86번)

1. 숫자, 문자열, 불리언의 경우 직접 값을 할당하여 변경하기
ex. this.setState({ count: this.state.count + 1 });

2.배열의 경우
concat, slice, spread operator, map, filter 등을 사용하여 배열을 수정하지 않고 새로운 배열을 생성하기

3. 객체의 경우
Object.assign() 또는 spread operator를 사용하여 객체를 수정하지 않고 새로운 객체를 생성하기

4. 함수형 setState
상태 업데이트가 이전 상태에 의존하는 경우 함수형 setState를 사용하여 안전하게 상태를 업데이트 하기
ex. this.setState(prevState => ({
  count: prevState.count + 1
}));

5. 라이브러리 사용
immutable.js나 immer와 같은 라이브러리를 사용하기



- setState는 동기적으로 동작하나요? 아니면 비동기적으로 동작하나요?
왜 비동기적으로 동작하나요? (87번)                                   

:비동기적으로 동작합니다.
React는 상태 변경을 바로 적용하는 대신에, 여러 상태 변경을 모아서 일괄 처리하는 방식인 batch update를 사용하기 때문입니다. batch update 로 인해 여러 setState 호출이 연속적으로 일어나도, React는 이를 모아서 한 번에 UI를 업데이트합니다.
이렇게 하면, 불필요한 렌더링과 DOM 업데이트를 줄여 성능을 향상시킬 수 있습니다.




- HTML과 React의 이벤트 처리 차이점에 대해 설명해주세요. (88번)

1. 이벤트 이름의 표기법
HTML: 대부분 소문자로 이벤트를 표기합니다. ex. onclick, onchange 등.
React: camelCase로 이벤트를 표기합니다. ex. onClick

2. 이벤트 핸들러의 할당
HTML: 문자열 형태로 JavaScript 코드를 전달   ex.<button onclick="handleClick()">
React: 함수 형태의 이벤트 핸들러를 전달  ex.<button onClick={handleClick}>

3. this 바인딩
React 클래스 컴포넌트에서 이벤트 핸들러를 사용할 때, 함수 내에서 this를 사용하려면 이벤트 핸들러를 바인드 해야함

ex. constructor(props) {
  super(props);
  this.handleClick = this.handleClick.bind(this);
}
 

4. 이벤트 객체
HTML: 원래의 브라우저 이벤트 객체를 전달받음
React: React는 원래의 브라우저 이벤트 객체를 감싸는 ** 합성 이벤트 객체를 전달함

(** 합성 이벤트 : React의 이벤트 처리 시스템의 일부로, 브라우저의 네이티브 이벤트를 감싸는 객체)
 
ex. 네이티브 이벤트
document.getElementById('myButton').addEventListener('click', function(e) {
    console.log(e);
});

ex2. React의 합성 이벤트
function MyComponent() {
    const handleClick = (e) => {
        console.log(e);  // 이 'e'가 React의 합성 이벤트입니다.
    };

    return <button onClick={handleClick}>Click me</button>;
}


5. 이벤트 위임
HTML: 각 요소에 개별적으로 이벤트 리스너를 부착
React: React는 내부적으로 이벤트 위임을 사용함. 최상위 레벨에서 단일 이벤트 리스너를 사용하여 이벤트를 감지하고, 적절한 핸들러에게 이벤트를 전달함


6. 이벤트 리스너 제거
HTML: addEventListener로 추가한 이벤트 리스너는 removeEventListener를 사용하여 명시적으로 제거
React: 컴포넌트가 언마운트될 때 React는 자동으로 해당 컴포넌트에 부착된 모든 이벤트 리스너를 제거






- ⭐ Key Props를 사용하는 이유에 대해 설명해주세요. (89번)

1. key값이 없는 element로 이루어진 트리에서 새로운 element가 추가될 경우, React는 <ul>의 모든 자식요소를 다시 변경하므로 비효율적이고 성능이 좋지 않습니다.
=> 자식 요소들이 key를 가지고 있다면 React는 key를 통해 기존 트리와 이후 트리의 자식들이 일치하는지 확인하므로 트리의 변환이 효율적으로 이루어집니다.

React는 DOM 업데이트를 효율적으로 수행하기 위해 가상 DOM과 비교(diffing) 알고리즘을 사용하는데 이때 고유한 key 값이 제공되면 어떤 항목을 추가, 변경 또는 제거해야 하는지 빠르게 판단할 수 있다.



- Ref의 용도에 대해 설명해주세요. (90번)
: render 메서드에서 DOM 요소나 React 요소에 직접적인 참조(reference)를 생성하는 데 사용된다.
Ref는 자식 컴포넌트를 직접 접근하여 수정할 때, DOM 엘리먼트에 접근하고 싶을 때 주로 사용합니다. 하지만 리액트 함수형 컴포넌트에서는 자식 컴포넌트에 직접 접근하여 수정하는 방법을 지양합니다.
따라서, 상태나 props를 통한 해결이 불가능한 경우에만 ref를 사용하는 것을 권장합니다.

Ref의 바람직한 사용 사례는 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때 사용 / 애니메이션을 직접적으로 실행시킬 때 사용 / 서드 파티 DOM 라이브러리를 React와 같이 사용할 때 등등이 존재합니다.



- 제어 컴포넌트와 비제어 컴포넌트의 차이에 대해 설명해주세요. (91번)
: React에서 폼 요소를 다룰 때 주로 사용되는 두 가지 접근 방식이다.

1. 제어 컴포넌트
사용자의 입력을 기반으로 자신의 state를 관리하고 업데이트
React에 의해 값이 제어되는 입력 폼 엘리먼트
React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState()에 의해 업데이트 됨
제어 컴포넌트는 사용자가 입력한 값과 저장되는 값이 실시간으로 동기화 됨
유효성 검사에 유용(ex. 유효한 데이터가 없는 경우 전송 버튼의 상태를 disabled로 표시)
사용자가 입력하는 모든 데이터가 동기화 되는 단점 -> 불필요한 리렌더링

ex) 사용자의 입력을 받는 컴포넌트에 event 객체를 이용해 setState()로 값을 저장하는 방식

const onChangeListener = (e) => {
    setInput(e.target.value);
  };

 return (
    <>
      <input onChange={onChangeListener} />
    </>
  );


2. 비제어 컴포넌트
기존의 바닐라 자바스크립트와 크게 다르지 않은 방식
(폼을 제출할때 submit 버튼을 클릭해야 요소 내부의 값을 얻어왔던걸 생각)
React state는 사용되지 않고,React의 ref를 사용해서 입력 요소에 직접 접근해 값을 얻음
사용자가 직접 트리거 하기 전까지는 리렌더링을 발생시키지도, 값을 동기화 시키지도 않음 (값이 실시간으로 동기화 되지 않음)


ex) 폼을 제출할때 submit 버튼을 클릭해야 요소 내부의 값을 얻어오는 방식

const inputRef = useRef();

const onClickListener = () => {
    console.log(inputRef.current.value);
  };

  return (
    <>
      <input ref={inputRef} />
      <button type="submit" onClick={onClickListener}>
        전송
      </button>
    </>
  );



* useRef
1. useRef() 는 heap영역에 저장되는 일반적인 자바스크립트 객체
2. 매번 렌더링할 때 동일한 객체를 제공 (heap에 저장되어 있기 때문에 어플리케이션이 종료되거나 가비지 컬렉팅될 때 까지, 참조할때마다 같은 메모리 값을 가짐)
3. 값이 변경되어도 리렌더링이 되지 않음 (같은 메모리 주소를 갖고있기 때문에 변경사항을 감지할 수 없음 -> 리렌더링 하지 않음)



- HOC (Higher-Order Components)에 대해 설명해주세요. (92번)
:  HOC(Higher-Order-Components)은 React에서 재사용 가능한 컴포넌트 로직을 구축하는 하나의 패턴으로, "컴포넌트를 인자로 받아 그 기능을 확장하거나 수정하여 새로운 컴포넌트를 반환하는 함수"입니다. 이를 통해 컴포넌트의 로직을 재사용하거나 확장하는 데 유용하게 사용됩니다.

HOC의 주된 목적은 여러 컴포넌트에 공통적인 로직이나 기능을 재사용하기 위한 것입니다. 

HOC 사용 시 주의할 부분은 Props, ref, 정적 메서드 등이 있습니다.

1. 같은 이름의 props가 충돌할 위험이 있기 때문에 이름을 고유하게 만들거나, HOC에서 사용하는 props를 분리하는 것이 중요합니다.

2. 원래 컴포넌트의 ref에 직접 접근할 수 없으므로, React.forwardRef API를 사용해야 합니다.
3. HOC를 사용하여 컴포넌트를 감싸면, 원래 컴포넌트의 정적 메서드가 새로운 컴포넌트에 자동으로 복사되지 않으므로  필요한 정적 메서드는 수동으로 복사하거나 다른 방법을 사용하여 관리해야 합니다.

React Hooks의 도입 이후, HOC의 필요성이 상대적으로 줄어 함수형 컴포넌트에서는 HOC 대신 custom hooks를 통해 재사용되고 있습니다.




- Context API에 대해 설명해주세요. (93번)
: Context API는 props를 사용하지 않아도, 전역적으로 데이터를 공유할 수 있게 합니다. 주로  "props drilling" 문제를 해결하기 위해 사용됩니다.


ex.
import { createContext } from 'react';

const MyContext = createContext();
// Context 는 리액트 패키지에서 createContext 라는 함수를 불러와서 만들 수 있습니다.


...

function App() {
  return (
    <MyContext.Provider value="Hello World">
      <GrandParent />
    </MyContext.Provider>
  );
}
// Context 객체 안에는 Provider라는 컴포넌트가 들어있습니다. 그리고, 그 컴포넌트간에 공유하고자 하는 값을 value 라는 Props로 설정하면 자식 컴포넌트들에서 해당 값에 바로 접근을 할 수 있습니다.


import { createContext, useContext } from 'react';

function Message() {
  const value = useContext(MyContext);
  return <div>Received: {value}</div>;
}
// 원하는 컴포넌트에서 useContext 라는 Hook을 사용하여 Context에 넣은 값에 바로 접근할 수 있습니다. 해당 Hook의 인자에는 createContext로 만든 MyContext를 넣습니다.
//이렇게 하면 중간 중간 여러 컴포넌트를 거쳐 전달하던 Props를 지워도 됩니다.




- React.Fragment에 대해 설명해주세요. (94번)
: Fragment는 React v16에 추가된 기능입니다.
JSX에서 여러 요소를 리턴하려면 이들을 하나의 부모 요소로 감싸야 합니다.
보통 이들을 <div>로 감싸는데, 이렇게 하면 필요 이상으로 <div>가 DOM에 추가되어 문서 구조가 복잡해집니다.
따라서, React.Fragment는 부모요소로 불필요한 DOM 요소 (ex. div)를 추가하고 싶지 않을 때 사용합니다.
사용법으로는 <React.Fragment> 와 <> 두가지 방법이 있습니다.





- Portal에 대해 설명해주세요. (95번)
: 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링 하는 기능
즉, 외부에 존재하는 DOM 노드가 React App DOM 계층 안에 존재하는 것처럼 연결을 해주는 포탈 기능을 제공
기존에 컴포넌트를 렌더링할 때는 children은 부모 컴포넌트의 DOM 내부에 렌더링 되어야 했는데, Portals를 사용하면 DOM의 계층 구조 시스템에 종속되지 않으면서 컴포넌트를 렌더링 할 수 있음 
주로 모달, 툴팁, 팝업 오버레이 등에 사용



- 에러 바운더리에 대해 설명해주세요. (96번)
: 에러 바운더리는 리액트를 사용하여 구현할 시 사용되는 컴포넌트 에러를 핸들링하는 방법
에러로 인해 컴포넌트가 깨지는 경우 대체 컴포넌트(fallback component)를 보여주도록 하는 것
Error Boundary는 클래스형 컴포넌트에서만 사용 가능하다.
함수형 컴포넌트에서 사용하기 위해서는 react-error-boundary 패키지를 설치하여 사용
(npm install react-error-boundary)



- 메모이제이션에 대해 설명해주세요. (97번)
: 메모이제이션은 "계산 비용이 높은 연산의 결과를 메모리에 저장해 두는 최적화 기법" 입니다.
이 후 동일한 입력에 대한 요청이 있을 때 이전에 저장한 결과를 반환함으로써 연산을 다시 수행하는 비용을 절감합니다.

리액트에서 렌더링 최적화를 위해 메모이제이션을 사용하는 방법으로는  React.memo, useMemo, useCallback이 있습니다.
1. React.memo는 "함수형 컴포넌트의 렌더링 결과"를 메모이제이션합니다.
"props"가 변경되지 않았다면, React는 이전 렌더링 결과를 재사용합니다.
이는 불필요한 리렌더링을 방지하여 성능을 향상시키는데 도움을 줍니다.

2. useMemo는 "연산 비용이 큰 함수의 결과"를 메모이제이션합니다.
"동일한 입력 값"에 대해서는 이전에 계산했던 값을 재사용할 수 있습니다.

3. useCallback은 "함수 자체"를 메모이제이션합니다.
이 함수가 "의존하는 값"들이 변경되지 않았다면, 동일한 함수 참조를 재사용합니다. 
이로 인해 자식 컴포넌트에 전달된 콜백이 변경되지 않아 불필요한 리렌더링을 방지할 수 있습니다.



- ⭐ 리액트에서 메모이제이션을 어떤 방식으로 활용할 수 있나요?
useMemo와 useCallback에 대해 설명해주세요.
React.memo와 useMemo의 차이에 대해 설명해주세요. (98번)


: 리액트에서 메모이제이션을 사용하는 방법으로는  React.memo, useMemo, useCallback이 있습니다.

<useMemo와 useCallback>
useMemo : "연산 비용이 큰 함수의 결과"를 메모이제이션
useCallback : "함수 자체"를 메모이제이션, 함수와 그 함수의 종속성 배열을 입력으로 받아, 종속성 배열에 있는 값들이 변경될 때만 함수를 다시 생성합니다.


<React.memo와 useMemo>
React.memo: 고차 컴포넌트(HOC)
클래스, 함수형 컴포넌트 모두 사용 가능
함수형 컴포넌트 "전체"를 대상으로 하여, 동일한 props로 호출될 때 재렌더링을 방지합니다.
주로 렌더링 성능 최적화에 사용됩니다.

useMemo: Hook
함수형 컴포넌트에서만 사용 가능
연산 비용이 큰 함수의 반환 값을 메모이제이션합니다.
컴포넌트 내에서 "특정 연산의 결과 값"을 저장하고 재사용하고자 할 때 사용됩니다.




- 리액트 관련 패키지 중에 제일 좋다고 생각한 것은 무엇인가요? (99번)
: 큰 규모의 애플리케이션에서 상태를 예측 가능하게 관리해주므로 Redux가 좋다 생각합니다.




- 리액트의 렌더링 성능 향상을 위해 어떻게 해야 하나요? (100번)

1. 메모이제이션 : useMemo와 useCallback 훅을 사용하여 연산 결과나 콜백 함수를 메모이제이션하여 불필요한 재계산을 방지
2. shouldComponentUpdate, PureComponent, React.memo 활용: 불필요한 렌더링을 방지하기 위해 컴포넌트의 업데이트 여부를 결정
3. useState의 함수형 업데이트 : setState를 사용할 때 새로운 상태를 파라미터로 넣는 대신, 상태 업데이트를 어떻게 할지 정의해 주는 업데이트 함수 삽입
4. 자식 컴포넌트의 props로 객체를 넘겨줄 경우 변형하지 말고 넘겨주기
5. key 값으로 index 사용하지 않기


'스터디 > 프론트 cs 스터디(23.08-23.11)' 카테고리의 다른 글

# 네트워크 예상 질문  (1) 2023.10.24
# React 예상 질문 - 4  (0) 2023.09.20
# React 예상 질문 - 2  (0) 2023.09.01
# HTML 예상 질문 - 1  (0) 2023.09.01
# React 예상 질문 - 1  (0) 2023.08.28