Top 40 ReactJS Interview Questions and Answers in 2024 | Simplilearn
Simplilearn.com
Redux, 리액트 없이도 사용할 수 있는 자바스크랩트 앱을 위한 예측 가능한 상태 관리 라이브러리. 일관적으로 동작하며, 클라이언트/서버/네이티브 환경에서도 실행됨. 테스트하기 쉬운 앱을 작성하도록 도와줌
📌 VSCode 익스텐션 추천
인스타그램 팔로워분들과 제가 추천하는 VSCode 익스텐션을 모아봤습니다.
1️⃣ GitLens by GitKraken
GitLens는 강력한 Git 통합 기능을 제공하여 코드를 이해하고 변경 사항을 추적하는 데 도움을 줍니다. 개발자가 커밋 히스토리와 작성자 정보를 쉽게 볼 수 있게 하며, Git을 GUI로 사용할 수 있습니다.
2️⃣ Todo Tree by Gruntfuggly
Todo Tree는 코드 내의 TODO와 FIXME 태그를 빠르게 찾아주고 시각적으로 하이라이트하여 작업 목록을 쉽게 관리할 수 있게 합니다. 이를 통해 개발자가 중요한 작업을 놓치지 않고 효율적으로 처리할 수 있습니다.
3️⃣ Project Manager by Alessandro Fragnani
이 익스텐션은 여러 프로젝트 간에 쉽게 전환하고 관리할 수 있는 기능을 제공합니다. 사용자가 프로젝트를 빠르게 검색하고 선택하여 작업 공간을 효율적으로 조직할 수 있게 돕습니다.
4️⃣ ES7+ React/Redux/React-Native snippets by dsznajder
이 익스텐션은 React, Redux 및 React Native 개발자에게 필수적인 코드 스니펫을 제공하여 개발 시간을 대폭 줄여줍니다. 자주 사용하는 코드 패턴을 빠르게 삽입할 수 있게 해줍니다.
5️⃣ Figma for VS Code by Figma
Figma 익스텐션을 사용하면 디자이너와 개발자 간의 협업이 용이해지며, VSCode 내에서 바로 Figma 디자인을 확인하고 코드로 변환할 수 있습니다. 이를 통해 프론트엔드 개발 속도를 높입니다.
6️⃣ Error Lens by Alexander
Error Lens는 코드 내의 오류와 경고를 즉시 강조 표시하여 개발자가 문제를 더 빠르게 식별하고 수정할 수 있게 합니다. 이는 코드 품질을 개선하고 디버깅 시간을 단축하는 데 기여합니다.
7️⃣ Auto Rename Tag by Jun Han
Auto Rename Tag는 HTML/XML 태그 작업을 보다 효율적으로 만들어 주며, 한 태그를 수정할 때 자동으로 짝을 이루는 태그도 수정해 줍니다. 이는 마크업 작업의 실수를 줄이고 속도를 높여줍니다.
8️⃣ Code Spell Checker by Street Side Software
이 익스텐션은 코드 내의 오탈자를 식별하여 개발자가 전문적이고 오류 없는 코드를 작성할 수 있도록 돕습니다. 여러 언어 지원으로 글로벌 프로젝트에도 유용합니다.
9️⃣ vscode-hanspell by Hyunrae Cho
vscode-hanspell은 한국어 맞춤법과 문법 검사를 지원하여 한국어로 주석을 달거나 문서를 작성하는 개발자들에게 매우 유용합니다. 마크다운 문법으로 블로그를 작성하는 경우 더 유용하게 사용할 수 있습니다.
React 면접 전 살펴보기 위한 Q&A 40가지 (2024년 ver)
React란 무엇인가요?
React는 사용자 인터페이스를 구축하기 위한 JavaScript 라이브러리입니다.
재사용 가능한 UI 컴포넌트를 생성하는 데 사용됩니다. 페이스북에서 개발하고 관리합니다.
React를 사용하는 이유는 무엇인가요?
동적 애플리케이션 쉽게 만들 수 있음: React를 사용하면 적은 코딩으로 더 많은 기능을 제공하여 동적 웹 애플리케이션을 쉽게 만들 수 있습니다.
성능 향상: React는 가상 DOM을 사용하여 웹 애플리케이션의 성능을 높입니다.
재사용 가능한 컴포넌트: 컴포넌트는 React 애플리케이션의 구성 요소로, 애플리케이션 전체에서 재사용할 수 있어 개발 시간을 크게 단축할 수 있습니다.
단방향 데이터 흐름: React는 단방향 데이터 흐름을 따르므로 디버깅이 쉽고 애플리케이션의 오류 위치를 파악할 수 있습니다.
쉬운 디버깅: 페이스북이 발표한 크롬 확장 프로그램을 사용하여 React 애플리케이션을 디버깅할 수 있어 프로세스가 빠르고 쉬워집니다.
React의 동작 방식은 어떻게 되나요?
React는 컴포넌트 기반으로 동작합니다. 컴포넌트는 애플리케이션의 독립적이고 재사용 가능한 코드 조각입니다. 각 컴포넌트는 자체 state와 props를 가지고 있습니다. React는 가상 DOM을 사용하여 변경된 부분만 실제 DOM에 반영합니다. 이를 통해 빠른 렌더링 속도를 보장합니다.
React의 주요 기능은 무엇인가요?
JSX: JSX는 JavaScript 문법 확장으로 React와 함께 사용되어 사용자 인터페이스의 모양을 설명합니다.
컴포넌트: 컴포넌트는 React 애플리케이션의 구성 요소이며, 사용자 인터페이스를 독립적이고 재사용 가능한 부분으로 분할합니다.
가상 DOM: React는 메모리에 실제 DOM의 경량화된 표현인 가상 DOM을 유지 관리합니다. 객체의 상태가 변경되면 가상 DOM은 실제 DOM에서 해당 객체만 변경합니다.
단방향 데이터 바인딩: React의 단방향 데이터 바인딩은 모든 것을 모듈화하고 빠르게 유지합니다.
높은 성능: React는 변경된 컴포넌트만 업데이트하므로 매우 빠른 웹 애플리케이션을 만들 수 있습니다.
JSX란 무엇인가요?
JSX는 JavaScript의 구문 확장입니다. React에서 사용자 인터페이스의 모양을 설명하는 데 사용됩니다. JSX를 사용하면 JavaScript 코드가 포함된 동일한 파일에서 HTML 구조를 작성할 수 있습니다.
웹 브라우저가 JSX를 직접 읽을 수 있나요?
웹 브라우저는 JSX를 직접 읽을 수 없습니다. 웹 브라우저는 일반 JS 객체만 읽도록 구축되었기 때문에 JSX는 일반 JavaScript 객체가 아닙니다. 웹 브라우저가 JSX 파일을 읽으려면 Babel을 사용하여 일반 JavaScript 객체로 변환해야 합니다.
가상 DOM이란 무엇인가요?
DOM은 Document Object Model을 나타냅니다. DOM은 HTML 문서를 논리 트리 구조로 표현합니다. 트리의 각 분기는 노드로 끝나고 각 노드에는 객체가 포함됩니다. React는 메모리에 실제 DOM의 경량화된 표현을 유지하는데, 이를 가상 DOM이라고 합니다. 객체의 상태가 변경되면 가상 DOM은 실제 DOM에서 해당 객체만 변경합니다.
Angular와 같은 다른 프레임워크 대신 React를 사용하는 이유는 무엇인가요?
동적 애플리케이션을 쉽게 만들 수 있음
가상 DOM을 사용하여 성능 향상
재사용 가능한 컴포넌트로 개발 시간 단축
단방향 데이터 흐름으로 디버깅이 쉬움
전용 도구로 쉽게 디버깅할 수 있음
ES6 표준과 ES5 표준의 차이점은 무엇인가요?
exports vs export, require vs import 등 ES6 구문이 ES5 구문과 다른 몇 가지 사례가 있습니다.
React 앱을 어떻게 만드나요?
NodeJS를 컴퓨터에 설치합니다. React 라이브러리를 포함한 많은 JavaScript 라이브러리가 포함된 npm이 필요하기 때문입니다.
명령 프롬프트나 터미널을 사용하여 create-react-app 패키지를 설치합니다.
VS Code나 Sublime Text 같은 원하는 텍스트 편집기를 설치합니다.
React에서 이벤트란 무엇인가요?
이벤트는 키 누름, 마우스 클릭 등 사용자나 시스템이 트리거할 수 있는 동작입니다. React 이벤트는 HTML에서는 소문자 대신 camelCase를 사용하여 이름이 지정됩니다. JSX에서는 HTML에서 문자열 대신 함수를 이벤트 핸들러로 전달합니다.
React에서 이벤트는 어떻게 생성하나요?
간단하게는 JSX에서 이벤트 핸들러 지정하여 생성할 수 있습니다. 컴포넌트의 JSX 엘리먼트에 이벤트 핸들러를 지정하며, 핸들러 함수는 중괄호({})로 감싸줍니다. 직접 이벤트 핸들러 함수 정의할 수도 있는데, 컴포넌트 내부에 이벤트 핸들러 함수를 정의하고, 함수는 일반적으로 arrow function 또는 메서드로 정의됩니다. 이때, 이벤트 핸들러 함수는 이벤트 객체를 매개변수로 받습니다. 이벤트 객체를 통해 이벤트에 대한 추가 정보(예: 타겟 엘리먼트, 마우스 좌표 등)에 접근할 수 있습니다.
React에서 합성 이벤트(synthetic events)란 무엇인가요?
합성 이벤트는 서로 다른 브라우저의 네이티브 이벤트에 대한 응답을 하나의 API로 결합하여 이벤트가 브라우저 간에 일관되도록 합니다. 이를 통해 애플리케이션이 실행 중인 브라우저에 관계없이 일관된 동작을 보장합니다. 여기서 preventDefault는 합성 이벤트입니다.
React에서 리스트가 어떻게 동작하는지 설명해주세요.
React에서는 일반 JavaScript에서와 마찬가지로 리스트를 생성합니다. 리스트는 데이터를 순서대로 표시하며, map() 함수를 사용하여 리스트를 순회합니다.
리스트에서 키(keys)를 사용해야 하는 이유는 무엇인가요?
키는 리스트에서 매우 중요한데 그 이유는 다음과 같습니다:
키는 고유 식별자로 리스트에서 어떤 항목이 변경, 추가 또는 제거되었는지 식별하는 데 사용됩니다.
또한 어떤 컴포넌트가 재렌더링되어야 하는지 결정하는 데 도움이 되므로, 매번 모든 컴포넌트를 렌더링하는 대신 업데이트된 컴포넌트만 재렌더링하여 성능을 높일 수 있습니다.
React에서 코멘트는 어떻게 작성하나요?
React에서 코멘트를 작성하는 방법은 두 가지가 있습니다:
한 줄 주석: // 로 시작
여러 줄 주석: /* 로 시작해서 */ 로 끝냄
React에서 화살표 함수란 무엇이고 어떻게 사용되나요?
화살표 함수는 React에 함수를 작성하는 간단한 방법입니다. 화살표 함수를 사용할 때는 생성자 내부에서 'this'를 바인딩할 필요가 없습니다. 이는 React 콜백에서 'this' 사용으로 인한 버그를 방지합니다.
React와 React Native의 차이점은 무엇인가요?
React:
출시일: 2013년
플랫폼: 웹
HTML 사용: 가능
CSS 사용: 가능
사전 지식: JavaScript, HTML, CSS
React Native:
출시일: 2015년
플랫폼: 모바일(안드로이드, iOS)
HTML 사용: 불가능
CSS 사용: 불가능
사전 지식: React.js
React 컴포넌트란 무엇인가요?
컴포넌트는 React 애플리케이션의 구성 요소이며, 하나의 앱은 일반적으로 여러 컴포넌트로 구성됩니다. 컴포넌트는 기본적으로 사용자 인터페이스의 일부입니다. 사용자 인터페이스를 독립적이고 재사용 가능한 부분으로 나눠서 별도로 처리할 수 있습니다.
React에는 두 가지 유형의 컴포넌트가 있습니다:
함수형 컴포넌트: 자체 state가 없고 렌더 메서드만 포함하므로 stateless 컴포넌트라고도 합니다. props를 다른 컴포넌트에서 데이터로 전달받을 수 있습니다.
클래스 컴포넌트: 자체 state를 보유하고 관리할 수 있으며, JSX를 반환하는 별도의 렌더 메서드가 있습니다. state를 가질 수 있으므로 Stateful 컴포넌트라고도 합니다.
React에서 render()의 용도는 무엇인가요?
각 컴포넌트에는 render() 함수가 필요합니다. 이 함수는 컴포넌트에 표시할 HTML을 반환합니다. 둘 이상의 요소를 렌더링해야 하는 경우 모든 요소를 <div>, <form>과 같은 하나의 부모 태그 안에 넣어야 합니다.
React에서 state란 무엇인가요?
state는 컴포넌트의 데이터나 정보를 포함하는 React의 내장 객체입니다. 컴포넌트의 state는 시간이 지남에 따라 변경될 수 있으며, 변경될 때마다 컴포넌트가 다시 렌더링됩니다. state 변경은 사용자 작업이나 시스템 생성 이벤트에 대한 응답으로 발생할 수 있습니다. 컴포넌트의 동작과 렌더링 방식을 결정합니다.
React에서 state는 어떻게 구현하나요?
React에서 state는 컴포넌트 내부에서 관리되는 상태 값으로, 시간에 따라 변할 수 있는 동적인 데이터를 저장하고 관리하는 데 사용됩니다.
React 16.8 버전부터 도입된 Hooks API 중 하나인 useState
훅을 사용하여 함수형 컴포넌트에서 state를 구현할 수 있습니다. useState
훅은 state 변수와 해당 변수를 업데이트하는 setter 함수를 반환합니다.
state 값을 업데이트하려면 setter 함수를 호출해야 하며, React는 자동으로 컴포넌트를 다시 렌더링하여 업데이트된 state 값을 반영합니다.
state는 컴포넌트 내에서 필요한 데이터를 저장하고 조작하는 데 사용되며, 사용자 인터랙션, 서버 데이터, 타이머 등 다양한 요인에 의해 변경될 수 있습니다.
React에서 state를 적절히 사용하면 동적이고 인터랙티브한 사용자 인터페이스를 구현할 수 있습니다. 컴포넌트 간에 state는 공유되지 않고 각 컴포넌트 내부에서 독립적으로 관리되므로, 필요한 최소한의 데이터만 state로 관리하는 것이 좋습니다.
컴포넌트의 state는 어떻게 업데이트하나요?
내장된 'setState()' 메서드를 사용하여 컴포넌트의 state를 업데이트할 수 있습니다.
React에서 props란 무엇인가요?
Props는 Properties의 약어입니다. 속성 값을 저장하고 HTML 속성과 유사하게 작동하는 React 내장 객체입니다. Props는 한 컴포넌트에서 다른 컴포넌트로 데이터를 전달하는 방법을 제공합니다. Props는 함수에 인수가 전달되는 것과 동일한 방식으로 컴포넌트에 전달됩니다.
컴포넌트 간에 props는 어떻게 전달하나요?
부모 컴포넌트에서 자식 컴포넌트로 props를 전달할 때는 JSX 내에서 속성(attribute)의 형태로 전달합니다. 자식 컴포넌트에서는 함수의 매개변수를 통해 전달받은 props에 접근할 수 있습니다. 전달받은 props는 자식 컴포넌트 내에서 읽기 전용입니다. 자식 컴포넌트는 props를 직접 수정할 수 없고, 변경이 필요한 경우 부모 컴포넌트에서 state를 변경하고 새로운 props를 전달해야 합니다.
state와 props의 차이점은 무엇인가요?
state:
용도: 컴포넌트에 대한 정보 보유
변경 가능성: 변경 가능
읽기 전용: 변경될 수 있음
하위 컴포넌트: 하위 컴포넌트가 액세스할 수 없음
Stateless 컴포넌트: state를 가질 수 없음
props:
용도: 다른 컴포넌트에 데이터를 전달하는 것을 허용
변경 가능성: 변경 불가능
읽기 전용: 읽기 전용
하위 컴포넌트: 하위 컴포넌트가 액세스할 수 있음
Stateless 컴포넌트: props를 가질 수 있음
React에서 higher-order 컴포넌트란 무엇인가요?
higher-order 컴포넌트는 다른 컴포넌트의 컨테이너 역할을 합니다. 이를 통해 컴포넌트를 단순하게 유지하고 재사용성을 높일 수 있습니다. 일반적으로 여러 컴포넌트가 공통 로직을 사용해야 할 때 사용됩니다.
두 개 이상의 컴포넌트를 하나로 어떻게 임베드할 수 있나요?
React에서 두 개 이상의 컴포넌트를 하나로 임베드하는 방법은 크게 두 가지가 있습니다.
첫 번째는 부모 컴포넌트 안에 자식 컴포넌트들을 배치하는 것입니다. 부모 컴포넌트의 JSX 안에 자식 컴포넌트들을 적절히 배치하면 됩니다. 이때 자식 컴포넌트들은 props를 통해 부모로부터 필요한 데이터를 전달받을 수 있습니다.
두 번째 방법은 합성 컴포넌트(Composite Component)를 사용하는 것입니다. 합성 컴포넌트는 여러 개의 컴포넌트를 조합하여 하나의 새로운 컴포넌트를 만드는 것을 말합니다. 이때 합성 컴포넌트 내부에서 자식 컴포넌트들을 적절히 배치하고, 필요한 props를 전달해주면 됩니다.
이렇게 함으로써 코드의 재사용성을 높이고, 컴포넌트 간의 결합도를 낮출 수 있습니다. 또한 UI의 일관성을 유지하면서도 유연하게 구조를 변경할 수 있게 됩니다.
클래스 컴포넌트와 함수형 컴포넌트의 차이점은 무엇인가요?
클래스 컴포넌트:
state를 보유하고 관리할 수 있음
stateless 컴포넌트에 비해 복잡함
모든 생명주기 메서드로 작업할 수 있음
재사용할 수 있음
함수형 컴포넌트:
state를 보유하거나 관리할 수 없음
이해하기 쉬움
생명주기 메서드로 작동하지 않음
재사용할 수 없음
컴포넌트의 생명주기 메서드를 설명해주세요.
getInitialState(): 컴포넌트가 생성되기 전에 실행됩니다.
componentDidMount(): 컴포넌트가 렌더링되어 DOM에 배치될 때 실행됩니다.
shouldComponentUpdate(): 컴포넌트가 DOM에 대한 변경 사항을 결정할 때 호출되며 특정 조건에 따라 "true" 또는 "false" 값을 반환합니다.
componentDidUpdate(): 렌더링 직후에 호출됩니다.
componentWillUnmount(): 컴포넌트가 영구적으로 파괴되고 마운트 해제되기 직전에 호출됩니다.
Redux란 무엇인가요?
Redux는 애플리케이션 상태를 관리하는 데 사용되는 오픈 소스 JavaScript 라이브러리입니다. React는 사용자 인터페이스를 구축하기 위해 Redux를 사용합니다. Redux는 JavaScript 애플리케이션을 위한 예측 가능한 상태 컨테이너로, 전체 애플리케이션의 상태 관리에 사용됩니다.
Redux의 구성 요소는 무엇인가요?
Store: 애플리케이션의 상태를 보유합니다.
Action: 저장소에 대한 정보의 출처입니다.
Reducer: 저장소로 전송된 액션에 대한 응답으로 애플리케이션의 상태가 어떻게 변경되는지 지정합니다.
Flux란 무엇인가요?
Flux는 Facebook이 웹 애플리케이션을 구축하기 위해 사용하는 애플리케이션 아키텍처입니다. 클라이언트 측 애플리케이션 내에서 복잡한 데이터를 처리하는 방법이며 React 애플리케이션에서 데이터 흐름을 관리합니다. 데이터의 단일 출처(저장소)가 있으며 특정 작업을 트리거하는 것이 저장소를 업데이트하는 유일한 방법입니다. 작업은 디스패처를 호출한 다음 저장소가 트리거되고 자체 데이터에 따라 업데이트됩니다. 디스패치가 트리거되고 저장소가 업데이트되면 변경 이벤트를 내보내 뷰가 그에 따라 다시 렌더링될 수 있습니다.
Redux는 Flux와 어떻게 다른가요?
Redux:
Redux는 애플리케이션 상태를 관리하는 데 사용되는 오픈 소스 JavaScript 라이브러리
저장소의 상태는 불변
단일 저장소만 가질 수 있음
Reducer 개념 사용
Flux:
Flux는 아키텍처이며 프레임워크나 라이브러리가 아님
저장소의 상태는 변경 가능
여러 저장소를 가질 수 있음
디스패처 개념 사용
React Router란 무엇인가요?
React Router는 React 위에 구축된 라우팅 라이브러리로, React 애플리케이션에서 경로를 생성하는 데 사용됩니다. 이는 가장 자주 묻는 React 인터뷰 질문 중 하나입니다.
React Router가 필요한 이유는 무엇인가요?
일관된 구조와 동작을 유지하고 단일 페이지 웹 애플리케이션을 개발하는 데 사용됩니다.
React 애플리케이션에 여러 경로를 정의하여 단일 애플리케이션에서 여러 뷰를 구현할 수 있습니다.
React 라우팅은 기존 라우팅과 어떻게 다른가요?
React 라우팅:
단일 HTML 페이지
사용자는 동일한 파일에서 여러 뷰를 탐색함
단일 파일이므로 페이지가 새로 고쳐지지 않음
성능 향상
기존 라우팅:
각 뷰는 새로운 HTML 페이지
사용자는 각 뷰에 대해 여러 파일을 탐색함
사용자가 탐색할 때마다 페이지가 새로 고쳐짐
성능이 느림
React 라우팅은 어떻게 구현하나요?
React에서 라우팅을 구현하기 위해 일반적으로 react-router-dom 라이브러리를 사용합니다. 주요 과정은 다음과 같습니다.
react-router-dom 설치: npm이나 yarn을 통해 라이브러리를 설치합니다.
index.js에서 BrowserRouter로 App 컴포넌트 감싸기: BrowserRouter는 HTML5의 History API를 사용하여 UI를 URL과 동기화합니다.
App.js에서 Route 컴포넌트를 사용하여 경로 설정: Route 컴포넌트의 path prop에 경로를, component prop에는 렌더링할 컴포넌트를 지정합니다.
Link 컴포넌트를 사용하여 다른 경로로 이동할 수 있는 링크 생성: Link 컴포넌트의 to prop에 이동할 경로를 설정합니다.
필요한 경우 파라미터나 쿼리 문자열을 사용하여 동적 라우팅 구현: URL 파라미터는 Route 경로에 콜론(:)을 사용하여 설정하고, useParams 훅으로 접근합니다. 쿼리 문자열은 location 객체의 search 속성을 통해 접근할 수 있습니다.
React에서 CSS 모듈을 사용하는 방법을 설명해주세요.
CSS 모듈 파일은 .module.css 확장자로 생성됩니다.
모듈 파일 내부의 CSS는 해당 모듈을 가져온 컴포넌트에서만 사용할 수 있으므로, 컴포넌트 스타일링 시 이름 충돌이 발생하지 않습니다.
React 컴포넌트는 어떻게 스타일링하나요?
React 컴포넌트를 스타일링하는 몇 가지 방법이 있습니다:
인라인 스타일링
JavaScript 객체
CSS 스타일시트
출처 : https://www.simplilearn.com/tutorials/reactjs-tutorial/reactjs-interview-questions
2023 JavaScript Rising Stars 리뷰
2023년 JavaScript 생태계의 주요 동향을 조망하는 'JavaScript Rising Stars'가 발표되었습니다.
이 중에서 가장 두각을 나타낸 프로젝트는 React로 구현된 UI 구성요소 모음인 'shadcn/ui'인데요. 이 프로젝트의 특이점은 NPM 패키지 형태로 제공되지 않으며, 사용자가 직접 소스 코드를 복사하여 사용한다는 점입니다. 'shadcn/ui'는 Tailwind CSS와의 호환성, React 서버 구성요소 지원, 우수한 문서화로 인기를 얻었습니다.
다만 Tailwind CSS가 많이 사용되지 않는 우리나라에서는 이 라이브러리가 향후에 인기를 얻을수 있을지는 모르겠네요.
또한, JavaScript 및 TypeScript 애플리케이션용 빠른 올인원 툴킷 'Bun', 새롭게 부상한 CSS-in-JS 라이브러리 'StyleX', 상태 관리 분야에서 'Zustand'가 주목을 받았습니다. 특히 'Zustand'는 기존의 Redux를 대체할 가능성에 대한 기대를 모으고 있는데요.
기존 Redux의 장점인 DevTools를 사용할수 있으면서도 보일러플레이트 코드가 상당히 적어서 대체되는건 아마도 시간문제일것 같습니다.
관심 있으신 분들은 사이트에 직접 방문해서 참고하시는것을 추천드립니다.
https://risingstars.js.org/2023/en#section-all
웹 개발에 대한 말말말 👨💻
Brian Birtles 님의 블로그를 의역/요약한 글입니다.
---
"2022년도 쯤에 썼던 글이지만, 2024년에도 유효한 내용이어서 끌올했습니다."
Mozilla를 퇴사한 후 웹 개발 전선에 뛰어들어 보니 놀라운 것들이 많았습니다. 웹 개발은 어렵고, 웹 개발자들은 사실 "개발잘알" 이었으며, 브라우저 개발자들이 비웃던 많은 프레임워크와 요행들이 아주 쓸만한 기술들이었습니다.
전부는 아니지만 많은 웹 개발자들이 웹 개발에 대한 선입견(?)을 가지고 있습니다. 브라우저 개발자였고 표준을 정의하는 개발자였던 저로써는 이해하기 힘든 내용이지만 몇 가지 공유하려고 합니다.
“웹 브라우저 개발자는 웹 개발에 대해 잘 안다”
웹 브라우저 개발자라면 웹 개발에 대해 1도 모르는게 없는 사람들이라고 생각하기 쉽습니다. 왜냐면, 브라우저를 만드는 사람들이니까요.
문제는, 웹 브라우저 만드는 게 정말 빡셉니다.
대부분의 브라우저 개발자들은 특정 영역을 아주 잘하는 사람들입니다. 그리고 대부분 C++이나 Rust와 하루 종일 씨름하고 있지 JavaScript는 거의 접할 기회가 없습니다. 심지어 엄청 큰 모노 레포지토리에 코드만 푸시 할 뿐, 그 이후의 일은 다른 사람이 맡아서 합니다.
그래서 브라우저 개발자들은 webpack과 씨름하는 것도, TypeScript 에러를 보는 것도, iOS Safari를 크롬처럼 길들이는 것도 (그 외 웹 개발자가 접하는 이슈 기타등등) 다 경험해본 적이 없을 겁니다. 그러니 브라우저 개발자들은 대부분의 웹 개발자들보다 찐 웹 개발에 대한 경험이 적습니다. 물론, 개발자 도구나 브라우저의 프론트엔드를 만드는 개발자들은 JS를 좀 더 많이 사용하기는 합니다. 다만, 이들도 현역 웹 개발자들의 문제를 모두 다 이해하는 것은 아닙니다.
웹 브라우저 개발과 웹 개발은 그냥 다른 영역입니다.
“웹 브라우저 표준을 정하는 사람들은 웹 개발을 정말 잘 아는 고수들 일거야”
표준을 정하는 건 법을 정하는 것과 같습니다. 둘 다 보이지 않는 수고가 많이 들어갑니다. 다만, 이 표준을 정하는 사람들도 대부분 브라우저 개발자들입니다.
웹 개발자 입장에서 하나의 표준이 무수히 많은 회의와 고수들의 정제된 토론 끝에 정해진다고 생각할 수 있습니다. 다만, 이 환상은 이 회의에 한번이라도 참여할 수 있다면 산산이 부서질 것입니다. 물론, 최선의 결과를 추구하는 것은 맞지만 때론 미팅에 참여한 누군가의 주도 아래 속전속결로 표준이 정해질 때도 많습니다. 심지어 자기 승진을 위해 표준에 넣을 기능을 배포하기도 합니다.
우선 욕만 하는 것 같아서 좀 덧붙이자면, 이 회의에 참여하는 개발자들은 모두 좋은 의도를 가진 선한 사람들입니다. 대부분 본인들과 속한 팀의 한계를 잘 알고 있고 그 속에서도 웹 개발자들의 의견을 최대한 수집하고 반영하고 소통하려고 합니다. 다만, 이를 잘 해내는 그룹은 아직까지 없었습니다.
두 번째로, 전 WHATWG 표준 (HTML과 DOM 표준)은 경험이 전무합니다. WHATWG는 표준을 정하는 방식이 비동기로 이루어지고 회의는 필요할 때만 한다고 알고 있습니다. 제 느낌 상 표준을 정하는 과정이 더 합리적인 쪽은 WHATWG였습니다. 하지만, 이들도 웹 개발에 대해 잘 알고 있다고 말하기 어렵습니다. 표준을 정하는 것과 웹 개발은 아주 다른 것이니까요.
“웹 개발자들은 웹 개발에 대해 잘 알 것이다”
브라우저 개발자 입장에서 새로운 기능을 배포하고 그 기능이 여기저기 기사로 실리고 개발자들이 X/트위터 같은 곳에서 인지도를 쌓는 것을 보면 흥분되고 보람찹니다. 이제 온 세상이 이 새로운 기능에 대해 알고 있다고 착각하기 쉽습니다.
현실은 그렇지 않습니다.
일본 Mozilla에서 개발하고 있을 때, 현직자 인터뷰를 한 적이 있습니다. 인터뷰 대상자들은 웹 개발자들이었습니다. 놀랍게도 그들은 10년 전에 배포된 CSS 기능도 모르고 있었고, 알려줬을 때도 뜨뜻미지근한 반응이었습니다. 이미 같은 기능을 jQuery와 WordPress로 잘 구현해서 쓰고 있었습니다.
오히려 개발자 도구에서 모바일 뷰를 볼 때, 옆에 아이폰 테두리가 안 뜨는 것에 대한 요구 사항이 있었습니다. 브라우저 개발자였던 저는 실망했지만 한편으로는 그들이 마주하는 현실을 깨닫게 되었습니다. 작은 스타트업에서 웹 앱 하나에 회사의 존망이 결정된다면, 새로운 웹 기능을 하나 하나 뜯어보고 있을 시간이 없습니다. 그들은 속도전을 하고 있고 하나라도 빠르게 개발하고 배포해야 하기에 이미 검증된 기술을 쓰지 새로운 기술을 실험해 볼 여유 따윈 없었습니다.
“브라우저는 SPA를 위해 만들어지지 않았다”
이 주장은 아마 초기부터 브라우저는 네트워크를 통해 컨텐츠를 로딩하고 점진적으로 배치한 후 렌더링하는 형태로 작동했기에 이쪽으로 최적화가 잘 되었고 SPA 처럼 동적으로 페이지를 조작하는데는 비효율적이라고 생각할 수 있습니다. 20년 동안 브라우저 개발자로 일해본 경험을 빗대어 보자면, 이제는 더 이상 유효한 주장이 아닌 것 같습니다. Firefox의 개발자 도구는 React와 Redux로 작성된 SPA입니다. 브라우저가 복잡하고 동적인 SPA에 최적화되지 않았다는 주장은 어불성설입니다.
물론, 모바일 브라우저에서 SPA를 위한 최적화가 되지 않았다 - 라는 주장은 어느 정도 수용할 수 있습니다. Firefox도 모바일에서는 성능을 위해 기존 HTML로 렌더링 하던 브라우저를 네이티브 브라우저로 바꿨기 때문입니다. 물론, 제가 해당 작업을 진행하지는 않아서 왈가왈부 할 입장은 아니지만 당시 기술 블로그에 따르면 앱 시작 시간 단축과 네이티브 제스쳐를 지원하기 위해 변경한 걸로 알고 있습니다.
“SPA는 결국 MPA로 대체될 거야”
View transition 표준에 참여했던 저로서는, 개인적으로 MPA를 흥미롭게 보고 있습니다. View transition은 사실 SPA를 염두에 두고 만들었지만, MPA도 유용하게 쓸 수 있습니다.
아무튼, “SPA는 결국 MPA로 대체될 거야”라는 주장으로 돌아와보면 사실 우리가 말하는 MPA가 뭔지 모르겠습니다.
제가 이해하기로 SPA는 하나 또는 두 개의 DOM 트리를 아주 오랫동안 JS로 조작하면서 앱을 만드는 형태고, MPA는 페이지 이동을 통해 서버에서 새로운 HTML을 받아오면서 앱을 조작하는 형태로 알고 있습니다. 이 네비게이션은 항상 최상위 네비게이션일 필요는 없고 iframe 같은 요소를 사용하고 있을 수 있습니다.
이 개념이 맞다면, 포토샵, 슬랙, 구글 맵, 피그마 같은 웹 앱들이 MPA로 어떻게 전환 될 수 있는지 상상이 안 갑니다. 이런 앱들을 MPA로 전환할 수 있다고 한들 - 개발 복잡도만 올라가고 사용자에게 실질적인 이득은 거의 없거나 SPA와 똑같을거라고 생각합니다.
지금 제가 만들고 있는 웹 앱도 MPA를 고려하지 않은 건 아니지만, 도저히 MPA로는 답이 안나와 SPA로 만들고 있습니다. “모든 앱이 MPA가 될거야” 라는 주장은 놀랍기만 합니다.
“모든 웹 사이트는 JavaScript 없이 돌아갈 수 있어야 해”
JavaScript 없이 웹 사이트 기능을 다 지원할 수 있다면 표준을 정말 잘 따르는 것이고 사실 이렇게 하기 위해 노력해야 하는 것은 맞습니다. 현존하는 모든 브라우저를 지원할 것이고 초기 렌더링을 막는 JS도 로딩할 필요가 없다는 뜻이니까요.
다만, 앞서 말한 것처럼 피그마나 포토샵이 JS 없이 어떻게 돌아갈지 상상이 가지 않습니다. 그리고 많은 사람들이 JS 때문에 접근성이 잘 고려되지 않는다고 생각하지만, 때론 접근성 기능을 넣는데 JS가 필요할 수도 있습니다.
Mozilla에 있을 때 배운 것 인데, Tab으로 요소를 이동한 뒤 화살표로 해당 요소 내에 있는 항목을 순회하는 것은 JavaScript가 없으면 구현할 수 없습니다. 심지어 저는 어떤 웹 사이트들은 JS를 더 (잘) 썼으면 좋겠습니다.
“웹 개발에서 빌드 과정은 필요 없다”
최근에 본 글 중에 이 같은 주장을 한 것을 봤습니다. 한평생 컴파일 언어로만 개발해온 저로서는 이해하기 힘든 부분입니다. 컴파일러는 대단한 기술입니다. 구닥다리 같은 내 코드를 몇 단계의 과정을 거쳐 컴퓨터가 수행할 수 있는 아주 효율적인 코드로 만들어주니까요.
물론, JavaScript 언어의 불완전함을 알고 있습니다. 컴파일 하기 까다로운 것도 이해합니다. 하지만, JavaScript 컴파일 단계도 분명 더 개선할 점이 있습니다.
이미지 에셋이나 정적인 HTML은 미리 빌드하는데 동의하는 웹 개발자들이, 코드를 정적으로 컴파일 해놓는 것에 반대하는 것은 저로서는 이해하기 조금 어렵습니다. 미리 컴파일 해놓을 수 있는데 왜 굳이 연산과 I/O를 런타임에서 하려고 하는 걸까요?
아무튼, 2024년에는 Rust/WASM 프레임워크들이 좀 더 각광을 받아서 이쪽 분야에서 두각을 나타냈으면 좋습니다.
“제 블로그가 웹 개발의 전형적인 예시”
브라우저 개발자에서 웹 개발자로 돌아온 저에게 웹 개발은 미지의 세계였습니다. 웹 개발자들이 주장하는 대부분의 것들이 놀라웠던 이유는 대부분 제가 직접 경험해보지 못했기 때문입니다.
Mozilla를 퇴사하고 지난 4년 간 저는 웹 개발자로 어떤 웹 앱을 만드는데 많은 시간을 할애했습니다. 그리고 동시에 이 블로그를 개발했습니다. 신기하게도, 이 블로그와 제가 만들고 있는 웹 앱은 웹 개발이라는 세계에서 양극단에 있는 것 같습니다. 서로 겹치는 기술이 없어요.
제가 하고 싶은 말은, 당신이 경험하고 있는 게 웹 개발의 전부는 아닐 겁니다. 웹 개발은 너무나 큰 세계고 우리의 상상을 아득히 뛰어넘는 곳입니다.
---
저도 제가 경험한 개발 세계는 극히 일부라고 생각하는데 비슷한 생각을 풀어낸 글이라 공유합니다. 비단 개발 뿐만 아니라 대부분의 영역이 여러 사람들의 집단 지성으로 이루어 졌을텐데, 한 개인이 그 영역을 다 이해하기란 불가능하다고 생각합니다. 물론 사람이 아니라 ChatGPT 같은 LLM이라면 가능할 수도? 😎
원글: https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#my-blog-is-representative-of-web-development-at-large
개발자에게 영감을 주는 리액트
저는 꽤 오랫동안 게임 개발자로 일을 해왔습니다.
실제로 게임 개발이라는 것은 단순히 게임을 개발하는 것을 벗어나서 다양한 툴들과 다양한 스크립트들도 작성하게 됩니다. 그러다가 저는 리액트를 접했습니다. 팀 내부에 런쳐나 툴을 사용하는 용도였죠. 처음 접한 리액트는 사실 좀 충격적이였습니다.
충격의 리액트
리액트를 마주했을 때 저는 MVX라고 불리는 패턴들을 좋아하는 개발자였습니다.
실제로 만드는 게임에도 UI를 만들 때, MVP 패턴을 이용하고 있었고, 최근에 직방에서 MV(R)P(Rx)도 조합해서 사용한적도 있습니다. 개인적으로 저에게 MVP나 MVVM과 같은 패턴은 꽤 구조적으로 편하고 유용했습니다.
그러다가 컴포넌트 기반의 리액트를 만나게 되었습니다. 아마도 많은 프론트엔드 개발자들이 리액트를 보고 받은 기분이 이런 기분이 아니였을까 싶기도 합니다. 마크업을 통해 표현하고, 그 안에 로직도 함께 포함시키는 컴포넌트 기반 개발은 실제로 제가 만드는 코드에도 영감을 많이 주었습니다.
대표적으로 액션이라고 하는 동기화 단위를 만들때 이전에 OOP로 클래스에 집중하던 코드를 함수형으로 바꾼다던가, 조금 더 데이터의 계층적 구조를 신경써서 컴포넌트화 한다던가 하는것들이 있었던 것 같습니다. 특히, 순수함수와 불변성에 대한 리액트의 철학은 개발 과정에서 저의 코드리뷰와 좀 더 좋은 코드로 향하는데 매우 큰 지식이 되었습니다. 무엇보다도 게임에 사용하던 툴들을 리액트를 통해 만들게 된것도 덤이였습니다.
(새로운 학습은 언제나 환영이니까요!)
두번째 만남 Roact
저는 게임 개발을 하다가 사이드 프로젝트로 로블록스라는 플랫폼에 게임을 만들기도 했습니다. 그때 Roact라는 걸 접했습니다. React를 Lua로 바꾸고, 동시에 로블록스라는 게임플랫폼에서 돌아가게 만든 라이브러리였습니다. 사실 처음에 Roact를 보고,
‘에이.. lua인데 되겠어?’
라는 생각을 먼저했는데 그 후에 나오는 라이브러리들을 보고 감탄을 많이 했습니다. Roact가 다른 로블록스에 게임 개발자들에게 영감을 주었는데 다양한 개발자들이 이를 발전시켜, Redux를 Lua로 만들어서 Rodux가 나오고, jsx/tsx 문법에 감탄한 나머지, roblox-ts 즉, Typescript를 Lua로 바꿔주는 라이브러리도 나오게 됩니다. 그리고 현재 로블록스 플랫폼은 tsx 마크업을 통해 UI를 만들수 있고, Hook을 통해 관리되고 컴포넌트 기반 UI가 가능해졌습니다.
왜 리액트일까?
State of JS 2022에 나온 프론트엔드 프레임워크 사용량 순위에 따르면, 리액트는 이미 7년 연속 정상을 차지하고 있습니다. 5년전만해도 프론트엔드 개발자들에게 이런 이야기를 많이 들어보셨을 겁니다.
“프론트엔드 개발은 4년에 한번씩 기술 스택이 바뀌는 곳이야”
실제로 이 말은 사실이였습니다. AngularJS, Ember.js, jQuery등 다양한 라이브러리와 프레임워크가 휩쓸고 그랬죠. 허나 이 말은 마치 무어의 법칙
이 깨지듯, 리액트가 프론트엔드는 휩쓸고 있다고 해도 과언이 아니죠. 물론, 더이상 배울 기술 스택이 없다는 의미는 아닙니다. React위에 쌓아 올라간 next.js나 Vue/Vite와 같은 새로운 조합이나, 떠오르는 샛별인 Svelte도 있죠. 이런 기술스택들이 예전에는 서로 경쟁관계 였다면 지금은 서로 영감을 주고 받습니다.
최근에 나온 React 19에 컴파일 컴포넌트는 Svelte를 떠올리게하고, React 18에 나온 서버 컴포넌트는 Next.js의 서버사이드 렌더링을 떠올리게하죠. 물론 본질적으로 다를진 모르지만 주고 받은 영감을 풀지 못했던 문제를 해결하는 방법으로 사용했을 확률이 큽니다.
그 관점에서 가장 많은 영감을 부여했던건 역시나 리액트입니다. 앱개발에 React Native나 VR/AR에 React VR이 그 예고, 위에 이야기 드렸던 로블록스의 Roact도 하나의 예가 됩니다.
그래서, 리액트가 그은 한획은 꽤 컸던것 같습니다. 게다가 리액트는 엄밀히 말하면 라이브러리이기 때문에 다양한 프레임워크나 다른 기술스택과 같이 사용하는게 가능해지면서,
모든 프론트엔드 개발자들이 jsx/tsx와 같은 확장 문법을 사용하고, 컴포넌트 기반 개발이 더 익숙하게 되었죠. 한마디로 말하면 리액트는 어느정도 프론트 엔드의 기초 학문이 되어버렸습니다.
모두를 위한 리액트
그래서 저는 주변에 새로운 기술을 배우거나 성장하고 싶은 개발자분들에게 “리액트"를 배워보라고 추천하곤 합니다. 그 분이 프론트엔드가 아닐수록 말입니다.
저도 리액트를 배우면서 제 프로그래밍 패턴이나 구현 방식이 많이 바뀌었고, 확실한 성장을 했기에 드릴 수 있는 추천이 아닌가 싶습니다. 2024년에 새로운 무언가를 배운다면, 리액트로 시작해보시는거 어떤가요?
게임으로 배우는 리액트
무엇부터 시작해야할지 어려우시다면, 콜로소와 함께 가장 빠르고 조금 쉽게 리액트를 배울 수 있는 ‘게임 프로젝트로 쉽고 빠르게 공략하는 핵심 모던 리액트’라는 강의를 추천드립니다. 네.. 제가 찍은 강의입니다 :) 저는 무언가를 배울때 게임을 통해 배우는게 저에겐 가장 빠른 학습 방법이였습니다. 그 방법을 그대로 가져왔습니다. 그리고, 무엇보다 웹개발자 관점이 아닌 제너럴리스트 관점에서 리액트를 쉽게 설명해드리고 풀어나갈 예정입니다 :)
아직 오픈 전 얼리버드를 진행중입니다!
4월 11일 커리큘럼 오픈을 하니, 오픈 전에 쿠폰을 받아 두시면 더욱 저렴하게 수강하실 수 있습니다!!
감사합니다.
쿠폰 링크 : https://bit.ly/3U4Rn9R
쿠폰 코드 : leedohaeng-70000
NextJS Pages Router에서 유저 데이터를 상태관리하기위해 redux를 사용했으나, 새로고침 시 데이터가 날라가는 문제를 해결하기 위해 persist gate를 사용했습니다. 하지만 redux persist gate를 사용하면 클라이언트 컴포넌트로 인지되는 문제가 있습니다. 궁금한 것 1) persist gate를 잘못써서 생긴 문제일까요? 아님 persist gate를 쓰면 안될까요? 2) 해결 방법으로 생각 해본 것은, "persist gate를 사용하지 않고 매 새로고침 시 저장되어있는 local storage에서 데이터를 새로 가져온다." 입니다. 3) ssr시 상태관리 새로고침 다른 방법으로 해결해본 경험 있으시면 아무렇게나 대답해주시면 감사하겠습니다!!! ----------------------------------------------- 문제의 코드 위치: https://github.com/bbookng/zippyziggy-v2/blob/main/frontend/zippy-ziggy/src/pages/_app.tsx 문제의 코드: import GlobalStyle from '@/styles/Global.style'; import useDarkMode from '@/hooks/useDarkMode'; import { media } from '@/styles/media'; import { darkTheme, lightTheme } from '@/styles/theme'; import type { AppProps } from 'next/app'; import { ThemeProvider, createGlobalStyle } from 'styled-components'; import normalize from 'styled-normalize'; import '@/styles/index.css'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import AppLayout from '@/layout/AppLayout'; import store, { persistor } from '@/core/store'; import { PersistGate } from 'redux-persist/integration/react'; import { Provider } from 'react-redux'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import 'toastify-js/src/toastify.css'; import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import DefaultHead from '@/components/Head/DefaultHead'; import Construction from './construction'; const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, // default: true }, }, }); function App({ Component, pageProps }: AppProps) { const { colorTheme, toggleTheme } = useDarkMode(); return ( <Provider store={store}> <PersistGate persistor={persistor}> <QueryClientProvider client={queryClient}> <ThemeProvider theme={colorTheme === 'dark' ? darkTheme : lightTheme}> <AppLayout toggleTheme={toggleTheme}> <Component {...pageProps} /> ... </AppLayout> </ThemeProvider> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> </PersistGate> </Provider> ); } export default App;
import DateRangePicker from "@wojtekmaj/react-daterange-picker"; import { useDispatch } from "react-redux"; import { dateFetch } from "components/feature/FetchSlice"; import styled from "styled-components"; type ValuePiece = Date | null; type Value = ValuePiece | [ValuePiece, ValuePiece]; export default function CustomCalendar() { const dispatch = useDispatch(); const [value, onChange] = useState<Value>([new Date(), new Date()]); return ( <CalendarBox> <Calendar>조회 기간</Calendar> <StlyedDateRangePicker onChange={onChange} value={value} onCalendarClose={() => { dispatch( dateFetch({ startDate: value[0]?.toISOString(), endDate: value[1]?.toISOString(), }) ); console.log(value); }} /> </CalendarBox> ); } <StlyedDateRangePicker>는 styled component로 만든 DateRangePicker 라이브러리 컴포넌트입니다. DateRangePicker 에서 날짜 2개를 선택하면 value라는 배열에 Date 객체 2개가 들어갑니다. 그리고 onCalendarClose 함수가 동작하면서 redux로 만들어놓은 startDate, endDate 객체에 각각 date를 toISOString() 처리한 값이 할당되는 로직입니다. 날짜를 선택하기 전에는 value={value}의 value 배열요소인 Date객체 값이 null 값이니까 type ValuePiece = Date | null; 타입지정을 해줬습니다. startDate: value[0]?.toISOString(), endDate: value[1]?.toISOString(), 근데 위 코드의 value[0], value[1] 에러가 나더라구요. 'value' is possibly 'null'.ts(18047) Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'Date | [ValuePiece, ValuePiece]'. Property '0' does not exist on type 'Date | [ValuePiece, ValuePiece]'. null 값일 수도 있다길래 옵셔널체이닝을 줬는데 여전히 에러가 발생합니다.. 해결방법을 도무지 모르겠네요.. 도와주시면 진심으로 감사하겠습니다ㅠㅠㅠ
안녕하세요! 타입스크립트가 워낙 까다로운 언어이다보니 많은 고민이 있으셨을 것 같네요! 근본적으로는 현재 value의 타입이 잠재적으로 null | Date | [ Date | null, Date | null ] 형태의 어레이와 결합된 복잡한 형태를 띄고 있기 때문에, 이러한 구조 자체가 TS에서 어느정도 지양해야할 패턴으로 보입니다. 하지만 외부라이브러리를 쓰시는 것으로 보여서 감수하고 해결 가능한 답변을 생각해보겠습니다! 먼저 질문자님께서 시도하셨던 방식에서 value는 array일 수도, 아닐 수도 있기 때문에 0번, 1번 인덱스에 접근하고자 하는 시도 자체가 타입에러를 내고 있는 듯 합니다. 따라서 이를 방지하기 위해, 먼저 타입가드 / 조건문 등의 방식을 통해 array형태 여부를 걸러서 케이싱을 해준다면 더 안전한 코드 작성이 가능해 보입니다. 작성시엔 여러 방식이 있지만, 코드의 가독성면에서 제일 좋아보이는 타입가드 코드를 첨부해두겠습니다!
안녕하세요, RN(Expo)로 React Navigation을 적용하다 오류가 해결되지 않아서 질문드립니다. expo를 통해 다음과 같이 index.js에 React Navigation을 적용했습니다. import { store } from "@/redux/store"; import MainScreen from "./screens/MainScreen"; import { Provider } from "react-redux"; import { NavigationContainer } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import LoginScreen from "./screens/LoginScreen"; export default function HomeScreen() { const Stack = createNativeStackNavigator(); return ( <Provider store={store}> <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Main" component={MainScreen} /> <Stack.Screen name="Login" component={LoginScreen} />{" "} </Stack.Navigator> </NavigationContainer> </Provider> ); } 그러나 다음과 같은 오류가 뜨며 빈화면만 보이더라구요ㅠ Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them. 찾아보니 NavigationContainer가 중첩되었다는 것 같은데, 저는 계속해서 그대로 강의를 따라가고 있었고, 따로 NavigationContainer를 적용한 파일이 존재하지 않습니다 ㅠ 다음 속성을 추가해도 오류가 해결되지 않습니다 ㅠ 아마 어디선가 부모에서 NavigationContainer가 적용된 것 같은데 찾을 수가 없네요 ㅠㅠ independent={true} 조금 더 찾아보니 expo-router랑 충돌이 난 거일 수도 있다는데 정확하게 모르겠네요 ㅠ
안녕하세요. redux를 recoil로 변경하면서 typescript도 같이 사용해보고 있는데 감이 잘 잡히지 않네요 타입스크립트에서 다른타입의 값을 가져와서 비교후 처리해야한다면 어떻게 해야할지 모르겠어서 질문을 드리게 되었습니다. 애초에 이러한 경우는 성립을 하지가 않는걸까요? 컴포넌트에서 deleteTagHandler에서 Tag타입으로 값을 받아와서 setRemoveToNoteTags()로 Tag타입의 매개변수 tag를 전달해주는데요 selector에서는 NotesList의 타입을 지원하고 있어서 그런거 같습니다... 가르침 부탁드리겠습니다 ㅠㅠㅠ 컴포넌트``` const setRemoveToNoteTags = useSetRecoilState(removeTagsSelector); const deleteTagHandler = (tag: Tag): void => { setTagsState({ type: "delete", tagsList: [tag] }); setRemoveToNoteTags(tag); }; ``` selector``` interface NotesList { mainNotes: Note[]; archiveNotes: Note[]; trashNotes: Note[]; editNote: null | Note; } const initialState: NotesList = { mainNotes: [...notes], archiveNotes: [], trashNotes: [], editNote: null, }; export const notesListState = atom({ key: "notesListState", // 고유한 키 default: initialState, // 초기 상태 }); export const removeTagsSelector = selector({ key: "removeTagsSelector", get: ({ get }) => {}, set: ({ get, set }, newValue: Tag) => { const notesList = get(notesListState); const removeTagFromNotes = (notes: Note[]) => { return notes.map((note) => { return { ...note, tags: note.tags.filter(({ tag }) => tag !== newValue.tag), }; }); ...... ```
안녕하세요, 요즘 next 13과 react 18 서버 컴포넌트에 대해서 본격적으로 파고 있는데 궁금한 점들이 여러가지 떠올라서 글 올립니다. 1. data fetching 방식의 변경 우선 기존에는 동적인 data fetching의 경우, getServersideProps를 통해서 페이지의 root에 전달해주고는 방식이 일반적이었는데 서버에서만 돌아가는 서버 컴포넌트가 나오면서 data fetching을 컴포넌트 단위로 할 수 있게되면, 기존에 사용하던 getServersideProps 같은 유틸 함수들은 사라지는건가요? 기존에는 정적 데이터면 getStaticProps, 동적 데이터면 getServersideProps, 유저 상호작용이 필요한 데이터면 client side useEffect를 많이 사용했는데 next 13부터는 이게 뭔가 뒤섞이는 것 같아서 혼란스럽네요. next 13을 위한 data fetching 패턴이나 방법론이 있나요? 2. 기존에 사용하던 상태 관리 프레임워크의 변화 위와 어느정도 연결되는 이야기입니다. 기존에 react-query를 많이 사용했는데 next 13부터 컴포넌트 레벨로 데이터를 요청할 수 있고 또 next 차원에서 요청 중복 제거를 지원하게되면 react-query 처럼 서버 상태관리와 캐싱을 강점으로 내세우는 프레임워크의 역할을 어떻게 되는건가요? 서버 상태를 컴포넌트 레벨에서 가져올 수 있다고 해도, 여전히 전역 상태 관리가 필요할 것 같은데 recoil, redux, zustand 같은 상태 관리 프레임워크도 계속 쓰게되는 것일까요? 계속 쓰게 된다고 하면 서버 컴포넌트와의 호환성은 어떻게 되는건가요? 만약 전역 상태 관리를 써야하는 컴포넌트라면 서버 컴포넌트가 될 수 없는 것인가요? 3. 서버 구성의 변경 다른 곳은 모르겠지만, 저는 next 백엔드를 단순히 요청을 전달하는 용도로만 쓰고 실제로 중요한 로직은 다른 백엔드 서버에서 처리하는 구조를 가지고 있었습니다. 하지만, next 13을 보니 서버 컴포넌트에서 DB 연결을 직접해서 데이터를 가져오는 예시들도 있더군요. 사이드 프로젝트라면 모르겠지만, 실 서비스에서도 서버 컴포넌트 - DB 직접 연결 이라는 구조가 성립할 수 있는건가요? 기존에 데이터를 취합하고 내려주던 백엔드 서버의 역할이 생략되는거라고 생각해도 되는건가요? 4. 왜 다시 20년 전으로 돌아가는거죠 제가 20년 동안 개발한 것은 아니지만, 예전에는 웹페이지를 서버에서 완전히 로드해서 내려주는 형태를 가지고 있었다고 배웠습니다. 그러다가 개개인의 기기가 스펙이 좋아지면서 서버 부하를 줄이고 클라이언트 쪽에서 역할을 분담하는 방식이 떴다고 들었어요. react도 처음에는 이런 프레임워크로 나왔다고 알고 있습니다. 그러다가 next, remix 같은 프레임워크들이 서버사이드 렌더링을 적극적으로 장려하면서 다시 회귀하고 있다고 들었습니다. 최근에는 react 마저 서버 컴포넌트를 발표했잖아요. 왜 이제와서 다시 서버 쪽에서 페이지를 로드하는 방식을 추진하고 있는건가요? 질문을 적고보니 좀 길어졌는데, 서핑을 좀 해봐도 마땅히 도움이되는 글이 별로 없어서 현직자들은 어떻게 생각하시는지 의견을 얻고자 질문 올립니다!
1번은 next.js 13버전 app에 대해서 공식문서(베타)를 보시면 없어짐을 아실 수 있습니다. 사실상 컴포넌트가 렌더링 되는 방식이 12에선 페이지 단위였다면 13에선 컴포넌트 단위로 변경되다보니 getStaticProps -> ISR or SSG, getServersideProps -> SSR로 페이지단위 렌더링 방식이 고정되는걸 서버컴포넌트와 클라이언트 컴포넌트로 컴포넌트 단위로 렌더링되는 방식이 변경되었다고 이해하시는게 더 나을거 같아요. 2번은 next.js13부터는 컴포넌트가 만약 상태라는걸 갖고 싶다면 클라이언트 컴포넌트를 사용하도록 강제화하고 있습니다. 서버컴포넌트에서 상태는 결국 디비라고 보시는게 더 편할거 같고 전역상태관리도 결국 top down이 아닌 bottom up 방식으로 변경되어감으로써 리덕스나 주스탄스 같이 정말 어플리케이션 전반에 걸치 상태라는 것은 이제 안쓰고 그 역할을 리액트쿼리 같은 캐싱기반으로 대체될것으로 전 생각하고 잇습니다. 3번은 아시다 싶이 가능이 한다는 것뿐이니 작은 서비스가 아닌 이상 백엔드 서버와 프론트엔드 서버는 분리되어야 관리도 용이하며 대용량 서비스에도 더 적합하기 때문에 next.js에 직접 디비를 연결할 일은 잘 없을것으로 보입니다. 4번은 아래의 deno 블로그에 올라온 글을 읽어보심이 더 좋을거 같습니다. https://deno.com/blog/the-future-and-past-is-server-side-rendering 제가 아는 지식선에서 설명을 드리자면 CSR에서 문제가 되었던 부분은 결국 프론트엔드에서 만드는 어플리케이션이 커짐에 따라서 한 화면을 이루는 번들 자체가 커져서 문제가 되었것으로 기억합니다. 추가적으로 모든 코드를 클라이언트에 돌리다보니 보안적인 문제도 있는것으로 알고 있습니다. 결국 SSR로 돌아온 것을 맞습니다만 jsp시절보다 낫다하는 면은 jsp시절에서는 클라이언트에서 렌더링하는 것 한벌, 서버에서 렌더링하는 것 한벌 짜야했던 점이 이제는 next.js와서 한벌로 가능해졌다는 점이 있고 위에서 설명드린 것처럼 한화면 모두 SSR인 것이 SSR과 SSG의 혼합 등으로 조금 더 나은 렌더링방식을 가져가는 것으로 보입니다.