멘토링에서 받은 키워드. 이전 게시글과 관련성이 깊어보인다. React를 아직 배우지 못했지만 구조를 이해할 수 있고, 선언적 프로그래밍 방식에 더욱 가까워진 느낌이다. JS에 대한 공부를 든든하게 해놔야할 것 같다.
React.js
(업데이트 전) React 공식 홈페이지, 첫 화면에 Declarative가 있다. 왜 선언형일까?
React 작동방식을 보아야할 것 같으니 (업데이트 후)tutorial을 시작해보았다.
React 앱은 Component로 만들어진다. 여기서 컴포넌트는 고유한 로직과 모양을 가진 UI의 일부이다.
React components는 마크업을 반환하는 javascript 함수이다.
function MyButton() {
return (
<button>I'm a button</button>
);
}
Mybutton
을 선언하면, 다른 컴포넌트에 중첩할 수 있다.
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
);
}
React의 마크업 언어는 대문자로 시작하여 HTML 태그와 구분할 수 있게 한다.
이 마크업 국문을 JSX라고 하며, React는 JSX 마크업 구문을 작성한다. JSX는 HTML보다 엄격하다고 한다.
복잡한 웹 UI로 구성된 프론트엔드 애플리케이션을 개발하고 관리하는 데 어려움을 겪고 있었다. 데이터가 변경될 때마다 뷰를 직접 변경하고 관리하는 것은 매우 고통스러운 일이었다.
➡️ 쉽게 말해서 데이터 변경시 UI의 상태를 직접 조작하여 업데이트 하는 것을 의미한다. 주로 명령형 프로그래밍에서 일어나는 방식인데, 데이터의 변경에 따라 UI를 직접 조작하여 원하는 결과를 얻는 것이다.
예로, JavaScript를 사용하여 DOM(Document Object Model)에 직접 접근하여 HTML 요소의 내용이나 스타일을 변경하거나, CSS를 직접 조작하여 레이아웃을 변경하는 것, 혹은 프레임 워크나 라이브러리 없이 순수 Javascript 코드로 UI를 관리하는 경우에도 뷰를 직접 변경하고 관리하는 것이라 볼 수 있다.
선언형 스타일 채택
리액트는 뷰를 자동으로 갱신하는 선언형 스타일을 채택했다. 데이터와 뷰를 분리한 것.
개발자가 UI 요소를 선언형 스타일로 작성한 후 뷰에 변경이 발생하는 경우 알아서 갱신한다. 뷰를 갱신할 때가 바로 선언형 스타일이 빛을 발하는 순간이다. 이를 내부 상태 (inner state) 변화라고 부른다.
이후 DOM비교(diffing) / 상태와 뷰의 보정(reconciliation)을 거친다. 내부적으로 가상 DOM을 이용, 이전 반영된 뷰와 새로운 뷰의 차이점을 찾고 업데이트 한다.
자바스크립트를 이용한 컴포넌트 기반 아키텍처
컨포넌트 기반 아키텍처는 React 이전에도 있었다. 관심사 분리, 느슨한 결합, 코드 재사용을 이 방식의 핵심을로 이점이 많다. 대신 순수 JS로 구현한 컴포넌트 기반 아키텍처는 없었다. 또한 React는 자바스크립트와 마크업을 한 곳에 두어 템플릿을 사용할 때처럼 매번 파일이나 언어를 바꾸는 수고를 덜어준다.
(html과 js파일을 분리하는 것은 관심사의 분리와는 다른 개념이다. 한가지 기능을 위해 두 개의 파일을 사용하는 것이기 때문)
강력한 추상화
React는 DOM을 쉽게 다룰 수 있고 같은 기능이지만 크로스 브라우징을 위해 다르게 구현할 수 밖에 없었던 인터페이스나 이벤트 핸들링을 정규화했다.
React는 왜 선언형일까? 선언형을 택했기 때문이다.
즉, 왜 React는 선언형을 택했을까? React가 선언형인 이유를 말해주는 특징들에 대해선 알고 있다. 그래서 왜?
"우리는 한 가지 문제를 해결하기 위해 React를 만들었습니다. 우리가 해결하고자 한 문제는 시간에 따라 변화하는 데이터를 다루는 거대한 애플리케이션의 개발입니다." - React 공식 홈페이지
완전히 리액트를 이해를 하기엔 어렵지만 선언형 프로그래밍 방식 또한
시간에 따라 변화하는 데이터를 다루기 위한 선택지라고 이해하면 될 듯하다.
근데 선언형 프로그래밍도 결국 명령형 프로그래밍을 해줘야 성립이 되는 것 아닌가?
그리고 리액트에서 강조하는 시간에 따라 변화하는 데이터는 무엇일까?
틀린 말은 아니다. 컴퓨터는 선언적 코드를 이해하지 못하며, 자신이 해야 할 의무와 그 방법을 단계별로 알려줘야만 하는 기계이다. 그러나 선언형 프로그래밍의 핵심은 순수한 선언적 코드를 작성하는 게 아니다. 명령적 코드를 구현 세부 사항만 나타내도록 제한된 영역 속에 밀어 넣는 것이다.
React 그 자체로는, 그저 UI 라이브러리로, JSX를 React elements를 생성하는 함수로 변환해 줄 뿐이다. 그리고 컴포넌트들의 생명 주기를 관리한다. 그게 전부이다. 정말 마법 같은 일은 렌더러에서 일어나는 것이다.
"이렇게 보일 것이다"라고 선언만 해두면, 실제로 그리는 것은 각 환경에 맞는 렌더러가 알아서 해 준다. 렌더링에 관한 선언과 구현이 분리되어 있기에 가능한 것.
이러한 유연성 덕분에 위에서 언급한 모든 환경에 React를 이식 할 수 있다. React를 사용하는 개발자는 컴포넌트와 관련 작업에만 집중할 수 있는 것.
렌더링에 관한 선언과 구현이 분리. 라는 말이 어려워서 더 찾아보았다.
import React from 'react';
function MyComponent() {
return <div>
<h1>Hello, React!</h1>
<p>This is a simple React component.</p>
</div>;
}
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1); // 상태(State) 변경하여 뷰 업데이트
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrement}>Increment</button>
</div>
);
}
React의 상태는 컴포넌트의 변경 가능한 데이터 저장소다. 독립적이면서 기능 중심인 UI와 논리의 블록이다. 변경 가능하다는 것은 상태 값을 변경할 수 있다는 것이다. 빗대어 설명하자면 컴포넌트를 속성과 상태가 있는 함수이고, 그 함수의 결과가 UI표현 뷰이다.
근데 또 흥미로운 걸 봤다.
이는 상태 객체가 없다. 컴포넌트 메서드 또는 다른 React의 라이프사이클 이벤트 또는 메서드를 갖지 않는다.
이 컴포넌트의 목적은 오직 뷰를 렌더링하는 것! 속성을 전달받아 UI 엘리먼트를 출력 처리하는 간단한 함수다.
상태비저장 컴포넌트는 예측할 수 있다는 이점이 있는데, 출력을 결정하는 입력이 한 가지뿐이기 때문이다. 에측가능성을 곧 이해가 쉽고 유지보수와 디버깅이 편리하다는 것을 의미한다.
실제로 상태를 가지지 않는 것이 React의 가장 바람직한 사례라고 볼 수 있다. 이를 많이 사용하고 상태저장 컴포넌트는 더 적게 사용할수록 좋다.
React는 함수형 스타일을 사용하여 상태비저장 컴포넌트를 위한 간결한 문법을 제공한다. 다시 말해 상태비저장 컴포넌트를 생성하려면 함수로 선언하라는 것이다.
리액트는 시간에 따라 변하는 데이터를 다루기 위해 선언적 스타일을 선택했다. 상태를 외부에서 수정할 수 없게끔 원칙을 세우고(함수형의 특징) 특정 상태와 속성을 컴포넌트로 만든다. 개발자는 컴포넌트를 선언하기만 하면된다. 데이터 변화에 따른 뷰에 대해선 걱정을 덜고 컴포넌트 기반으로 고민할 수 있게 해준다. 상태 저장 컴포넌트보다 상태 비저장 컴포넌트를 늘릴 방법은 무엇이 있을까? 🤔
결론까지 도달했을 때 방향이 확실한지 또 헷갈린다. 리액트를 써본 적이 없기 때문에... 얼른 배우고 실무에 상태에 대한 개념을 적용할 수 있기를 바래본다!
가치 있는 정보 공유해주셔서 감사합니다.