하위 컴포넌트가 다이얼로그 하단에 렌더링되고, 실제 dialog컴포넌트를 사용하는 signupdialog컴포넌트를 살펴보면 Specialization을 위한 props인 title, message에 값을 넣어주고 있으며 사용자로 부터 닉네임을 입력받고 가입하도록 유도하기 위해 <input>과 버튼 태그가 들어있습니다 이 두개의 태그는 모두 props.children으로 전달되어 다이얼로그에 표시됩니다. 이러한 형태로 containment와 Specialization을 동시에 사용할 수 있습니다!!!!
이렇게 useState()를 사용하여 count값을 state로 관리하는건데 이 코드에서 state의 변수명과 함수가 각각 count, setCount로 되어있는것을 볼 수 있지?
버튼 누르면 setCount()함수 호출해서 카운트 1증가시킴 그리고 count값 변경되면 컴포넌트 재렌더링되면서 새로운 카운트값 표시됨.
또 많이 쓰이는 훅은 useEffect()!
이 이팩트라는것은 서버에서 데이터를 받아오거나 수동으로 DOM을 변경하는 등의 작업을 말함 왜 이걸 이팩트라고 불러? 이 작업들이 다른 컴포넌트에 영향을 미칠수있고, 렌더링중에는 작업이 완료될수없기때문임!
이 useEffect는 클래스 컴포넌트에서 제공하는 생명주기 함수인 componentDidMount(), componentDidUpdate(), componentWillUnmount()와 동일한 기능을 하나로 통합해서 제공함 그래서 useEffect()훅만으로 생명주기 함수와 동일한 기능 수행 가능
useEffect(이팩트 함수, 의존성 배열);
첫번째 파라미터로는 이팩트 함수가 들어가고 두번째 파라미터로는 의존성 배열이 들어갑니다.
의존성 배열이란 말 그대로 이 이펙트가 의존하고있는 배열인데 배열안에 있는 변수중에 하나라도 값이 변경되었을때
아까 사용했던 useState훅에 추가로 useEffect()훅을 사용한것이다. useEffect()함수를 사용하여 생명주기 함수의 기능을 동일하게 수행하도록 만든것인데 useEffect()안에 있는 이펙트 함수에서는 브라우저에서 제공하는 API를 사용해서 document의 title을 업데이트한다. 이 title은 크롬 브라우저에 나오는 탭의 제목이담.
위에처럼 useEffect를 의존성 배열없이 사용한다면 처음 컴포넌트가 마운트 되었을때 실행되고, 이후 컴포넌트가 업데이트 될때마다 실행된다.
또한 이 이펙트 함수는 컴포넌트 안에서 선언되자나 맞지? 그래서 props와 state에도 접근가능
보면 count라는 state에 접근할수있잖아.
그렇다면 componentWillUnmount()와 동일한 기능은 useEffect로 어떻게 구현이가능할까?
실제로 각 페이지별로 html 파일이 따로 존재하며 페이지를 이동하게 될 경우 브라우저에서는 해당 페이지의 html파일을 받아와서 화면에 표시해준다!!
근데 페이지가 수많아지면 어떻게 관리를 해야하지?
이런 문제를 해결하기 위하여 나온 것이 바로 SPA(single page application)임.
이건 말그대로 하나의 페이지만 존재하는 웹 또는 어플리케이션임. 페이지가 여러개면 MPA 하나면 SPA (처음에는 이 HTML파일의 바디태그 내부가 텅 비어있다가 해당 페이지에 접속할때 그 페이지에 해당하는 콘텐츠를 가져와서 동적으로 BODY태그 내부를 채워넣게됨.
자바스트립트의 함수
함수는 입력을 받아서 정해진 출력을 하는 것
여기서 함수의 입력을 파라미터 또는 인자라고함
자바스크립에서 함수를 정의하는 방법은 두가지인데 첫번째는 FUNCTION SATEMENT이고 두번째는 ARROW FUNCTION EXPRESSION을 사용하는 방법임.
FUNCTION STATEMENT를 사용하였을때
function sum(a,b) {
return a+b;
}
ARROW FUNCTION EXPRESSION을 사용하였을때
const multiply = (a,b) => {
return a*b;
}
리액트는 자바스크립트 라이브러리임 라이브러리는 자주 사용되는 기능을 정리해 모아 놓은 것
그럼 사용자 인터페이스를 만들기 위한다는것은 무슨 의미일까
사용자 인터페이스는 UI라고 하는데 이건 사용자와 컴퓨터 프로그램이 서로 상호작용을 하기 위해 중간에서 서로간에 입력과 출력을 제어해주는 것이 바로 UI임.
걍 우리가 보는 버튼이나 텍스트 입력창같은거임. 히히
리액트는 대표적인 자바스크립트 UI 라이브러리임.
뭐 정리하자면 리액트는 사용자와 웹사이트의 상호작용을 돕는 인터페이스를 만들기 위한 자바스크립트 기능 모음집 정도!
리액트는 빠른 업데이트를 위해 내부적으로 Virtual DOM이라는 것을 사용함.
쉽게 설명해보자면 Virtual DOM은 말 그대로 가상의 DOM임. DOM은 DOCUMENT OBJECT MODEL의 약자로 웹페이지를 정의하는 하나의 객체라고 생각하면됨.
쉽게말해서 하나의 웹사이트에 대한 정보를 모두 담고 있는 큰 그릇이라고 보면됨.
기존의 방식으로 화면을 업데이트 하려면 DOM을 직접 수정해야하는데 이것은 성능에 영향을 크게 미치고 비용도 굉장히 많이듬. (수정할 부분을 DOM의 데이터에서 모두 찾아야 하기 때문)
하지만 리액트는 DOM을 직접 수정하는 것이 아니라 업데이트해야할 최소한의 부분을 검색하고 검색된 부분만을 업데이트하고 다시 렌더링하면서 변경된 내용을 빠르게 사용자들에게 보여줌.
컴포넌트는 구성요소라는 뜻. 리액트는 모든 페이지가 컴포넌트로 구성되어있고, 하나의 컴포넌트는 또 다른 여러개의 컴포넌트의 조합으로 구성될 수 있음. 따라서 리액트로 개발을 하다보면 레고블록을 조립하는 것처럼 컴포넌트를 조합해서 웹사이트를 개발하게됨.
재사용성! 객체지향프로그래밍에서 등장하는데 소프트웨어 개발에 있어서 매우 중요함. 이건 다시 사용이 가능한 성질인데 이 재사용성은 의존성 문제말고도 여러가지 호환성 문제도 발생할수있음 따라서 재사용성이 높게 개발하는것이 좋음
다시 말하자면 다른 모듈에 의존성을 낮추고 호환성 문제가 발생하지 않도록 개발해야한다!!
이러한 재사용성이 높아지면 개발 기간이 단축됨. 기존에 개발해둔 모듈을 곧바로 재사용하여 개발하면 되기때문에 개발기간을 많이 줄일수있음.
또한 유지보수가 용이함. 소프트웨어에서 공통으로 사용하는 모듈에 문제가 생기면 해당 모듈만 수정해서 다시 배포하면되기때문!
이렇게 재사용성이 높게 개발을 하면 버그를 찾기에도 훨씬 수월함. 재사용성이 높다? -> 모듈간의 의존성이 낮다
따라서 리액트 컴포넌트를 개발할때 항상 쉽고 재사용 가능한 형태로 개발하는 것이 중요함.
근데 리액트는 높은 상태 관리 복잡도를 가지고있음. state라는 개념이 있는데 쉽게말해 리액트 컴포넌트의 상태를 의미함. virtual dom은 바뀐 부분만을 찾아서 업데이트한다고 했는데 바뀐 부분이라는 것은 state가 바뀐 컴포넌트를 의미함. 따라서 state는 리액트에서 중요한 부분임.
성능 최적화를 위해 state를 잘관리하는 것이 중요함.
따라서 상태관리를 할땐 redux등의 외부 상태관리 라이브러리를 사용하는 경우가 많음. ㅈㄴ어렵다는 소리 ㅠㅠ
jsx는 자바스크립트 확장 문법임. jsx언어는 자바스크립트와 연관이 있으며, 자바스크립트의 문법을 확장시킨것.
jsx = 자바스크립트 + XML/HTML임.
대충 보자면
const element = <h1>Hello world</h1>;
이렇게 자바스크립트와 html코드가 결합되어있음.
이 위에 코드가 하는 역할은 element라는 변수에 h1태그로 둘러싸인 문자열을 저장하는것.
jsx는 내부적으로 html코드를 자바스크립트로 변환하는 과정을 거치게됨. 그래서 jsx코드를 작성해서 최종적으로는 자바스크립트 코드가 나오게 되는것.
이때 jsx코드를 자바스크립트 코드로 변환하는 역할을 하는 것이 바로 리액트의 createElement()라는 함수.
첫번째 파라미터로는 엘리먼트의 유형을 나타냄(type) 이 유형으로는 div나 span같은것들, 다른 리액트 컴포넌트같은 것들 있잖아 그런것들이 올 수 있음.
두번째 파라미터로는 props가 들어가게됨.
세번째로는 children이 들어가게되는데 이 children이란 현재 엘리먼트가 포함하고 있는 자식 엘리먼트.
props란 개념은 추후에 다룰것임! 겁나게 어렵기 때문!
이렇게 jsx를 사용하면 createElement를 사용했을때보다 좀 더 간결하고 가독성이 올라가기에 jsx를 사용하는 것을 추천.
그리고 jsx를 사용하면 injection Attack이라 불리는 해킹을 방어할 수 있어서 보안성이 올라감.
const title = response.potentiallyMaliciousInput
const element = <h1>{title}</h1>
//이 코드는 안전함
이렇게 title이라는 변수에 잠재적으로 보안 위험의 가능성이 있는 코드가 삽입되었지만 jsx코드에서는 괄호를 사용하여 title변수를 삽입하고있음.
-> ReactDOM은 렌더링 하기 전에 임베딩(삽입)된 값을 모두 문자열로 변환하여서 명시적으로 선언되지 않은 값은 괄호 사이에 들어갈수없음( 만약 입력창에 문자나 숫자같은 일반적인 입력값이 아닌 소스코드를 입력하여서 해당 코드가 실행이되어버리면 해킹이 될수 있으나 이러한 특징이있어 방어가능)
이렇게 html 코드 사이에 괄호를 사용해서 변수가 아닌 formatName(user)라는 자바스크립트 함수를 호출.
만약 사용자의 이름에 따른 인사말을 표현하고 싶다면?
function greeting(user) {
if (user) {
return <h1> Hello, {formatName(user)}!</h1>
}
return <h1>Hi stranger</h1>
}
그럼 children을 정의하고싶다면?
그냥 하위태그를 상위태그로 감싼다고 생각하면됨.
const element = (
<div>
<h1>안녕</h1>
<h2>리액트 공부하쟈</h2>
</div>
);
이렇게 하면 div태그의 children은 h1과 h2가 됨.
엘리먼트는 리액트 앱을 구성하는 요소를 의미함. 리액트 공식 홈페이지에서는 엘리먼트는 리액트 앱의 가장 작은 빌딩 블록들이라고 정의하고있음.
엘리먼트는 원래 웹사이트에 대한 모든 정보를 담고있는 객체인 DOM에서 사용하는 용어임.
하지만 DOM엘리먼트와는 다르게 리액트 엘리먼트가 따로있음.
DOM엘리먼트는 웹에서 개발자도구 켜서 나오는것들.
실제 브라우저의 DOM에 존재하는 엘리먼트는 DOM엘리먼트가 되는 것이고 리액트의 Virtual DOM에 존재하는 엘리먼트가 리액트 엘리먼트가 되는것임
즉, 리액트 엘리먼트는 DOM 엘리먼트의 가상 표현
엘리먼트는 컴포넌트 유형 과 속성 및 내부의 모든 자식에 대한 정보를 포함하고있는 일반적인 자바스크립트 객체.
이러한 엘리먼트는 불변성이라는 특징을 가지고있는데 엘리먼트는 한번 생성이되면 바꿀수 없기때문에 엘리먼트를 업데이트 하기 위해서는 다시 생성해야한다.
function tick() {
const element = (
<div>
<h1>안녕 리액트!</h1>
<h2> 현재 시간: {new Date().toLocaleTimeString()}</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
이 tick이라는 함수를 정의하고있는 코드는 현재 시간을 포함하고 있는 엘리먼트를 생성하여 root div에 렌더링하는 역할을 함.
또한 자바스크립트의 setInterval()함수를 사용하여서 tick()함수를 1초에 한번씩 호출하고있음.
이 코드의 실행결과는 매초 화면에 새로운 시간이 나오는데 이것은 tick함수가 호출될때마다 기존 엘리먼트를 변경하는것이 아니라, 새로운 엘리먼트를 생성하여 바꿔치기 하는것임.
근데 여기서 실제로 현재 시간을 초단위로 띄우는 걸 웹으로 표현할때
이렇게 toLocaleTimeString()함수를 사용하여서 실제 시간을 받아온후에 그냥 index.js에 컴포넌트를 가져와서 화면에 나타내기만 하면 되는게 아니라 index에서도 추가작업이 필요함.
초당 새로 업데이트 되는 걸 표현해주기 위하여
이렇게 setInterval함수를 사용하여서 매초마다 주기적으로 업데이트가 진행이 될수있도록 해주어야함.
리액트는 컴포넌트 기반의 구조임!
모든 페이지가 컴포넌트로 구성되어있고 하나의 컴포넌트는 또 다른 여러개의 컴포넌트의 조합으로 구성
이렇게 컴포넌트를 반복적으로 사용함으로써 전체 코드의 양이 줄어 자연스레 개발시간과 유지보수 비용도 줄일수있음.
이러한 리액트 컴포넌트에서의 입력은 props라는 것이고 출력은 앞에서 배운 리액트 엘리먼트가됨
결국 리액트 컴포넌트가 해주는 역할은 어떠한 속성들을 입력으로 받아서 그에 맞는 리액트 엘리먼트를 생성하여 리턴해주는것.
쉽게 말하자면 리액트 컴포넌트는 만들고자하는대로 props(속성)을 넣으면 해당 속성에 맞춰 화면에 나타날 엘리먼트를 만들어주는 것.
더 쉽게말하자면 붕어빵 틀 같은것임 여기서 붕어빵 틀은 컴포넌트, 각 붕어빵들은 엘리먼트
객체지향의 개념에서 나오는 클래스와 인스턴스의 개념과 비슷.
props는 리액트 컴포넌트의 속성임. 붕어빵을 만들때 컴포넌트라는 붕어빵 틀에 어떤 props를 넣는지에 따라 각기 다른 엘리먼트들이 나오는것임.
이처럼 props는 리액트 컴포넌트에서 눈에보이는 글자나 색 등의 속성을 바꾸고 싶을때 사용하는 컴포넌트속의 재료.
props는 컴포넌트에 전달할 다양한 정보를 담고 있는 자바스크립트 객체
이러한 props를 통하여 컴포넌트를 통해 엘리먼트를 생성하면 이 생성된 엘리먼트에 대해서는 더이상 props값을 변경할수가없음. 따라서 다른 props값을 넣어주고싶다면 다시 컴포넌트에 값을 넣어서 새로운 엘리먼트를 만들어주면댐.
우리가 함수를 구분지을때에는 pure함수와 impure함수로 구분을 하는데 이때
pure함수에 대해서 먼저 설명을 해보자면
function sum(a, b) {
return a+b;
}
이러한 간단한 함수를 예시로 들어보자면 a와b라는 파라미터의 값을 받아서 그 둘의 합을 리턴할때 a,b라는 파라미터의 값을 변경하지않고있음 -> 이경우가 pure하다.
impure함수를 보면
function withdraw(account, amount) {
account.total -= amount;
}
이 함수를 보자면 account와 amount라는 파라미터를 받아서 account의 total이라는 값에서 amount라는 값을 빼는 함수임 쉽게 말하자면 은행 계좌에서 출금을 하는 함수. 이 경우를 보면 입력으로 받은 파라미터인 account의 값을 변경했으므로 impure한것임.
왜 이얘기를 했냐하면
리액트 공문에 모든 리액트 컴포넌트는 그들의 props에 관해서는 pure 함수 같은 역할을 해야함.
더 쉽게말하자면 리액트 컴포넌트는 props를 직접 바꿀순없고 같은 props에 관해서는 항상 같은 결과를 보여줄것!
jsx를 사용하면 키-값 쌍의 형태로 컴포넌트에 props를 넣을수있음
function App(props) {
return (
<Profile
name="태영"
introduction="안녕 난 태영이야"
viewCount={1500}
/>
);
}
띄어쓰기 자꾸 왜이러는데...
App 컴포넌트가 나오는데 이 안에서 profile컴포넌트를 사용하고있음
이 profile컴포넌트 안에 name, introduction, viewCount라는 세가지 속성이 있는데 이 속성의 값이 모두 profile컴포넌트에 props로 전달되며, props는 아래와 같은 형태의 자바스크립트 객체가됨.
{
name:"태영",
introduction: "안녕 난 태영이야",
viewCount: 1500
}
주의할점은 props에 값을 넣을때에 문자열 이외에 정수, 변수, 그리고 다른 컴포넌트등이 들어갈 경우에는 중괄호를 사용하여서 감싸주어야함.
MPA(Multi-page-application)는 여러 페이지로 이루어진 어플리케이션을 말합니다 즉 mpa는 사용자가 다양한 페이지로이동하면서 애플리케이션을 사용하는 전통적인 방식입니다. 반면에 리액트는 SPA(single-page application)를 지향합니다 SPA는 한개의 페이지로 이루어진 어플리케이션으로 새로운 페이지를 로딩할 필요없이 화면이 동적으로 바뀌는 것을 특징으로 합니다. SPA는 사용자 경험과 속도 측면에서 우수한 성능을 보여주기때문에 최근에는 많은 웹 어플리케이션이 SPA로 구현됩니다.
컴포넌트
클래스형 컴포넌트
리액트에서 클래스형 컴포넌트는 ES6의 클래스 문법을 사용하여 정의되는 컴포넌트 입니다. 클래스형 컴포넌트는 React.Component클래스를 상속받아서 만들어지며 render()메소드를 포함하고 있습니다.
다음 코드는 React.Component클래스를 상속받아 MyComponent라는 클래스형 컴포넌트를 정의합니다.
import React from ‘react’;
class MyComponent extends React.Component {
render() {
return <h1>Hello, World</h1>;
}
}
클래스형 컴포넌트는 다음과 같은 특징이 있습니다.
this.props를 사용하여 부모컴포넌트로부터 전달된 속성값에 접근할 수 있습니다.
state객체를 사용하여 컴포넌트 내부 상태를 관리할 수 있습니다.
this.setState()메소드를 사용하여 state를 업데이트 할 수 있으며
state가 변경될때마다 render()메소드가 다시 호출됩니다.
함수형 컴포넌트
함수형 컴포넌트는 리액트에서 컴포넌트를 정의하는 또 다른 방법입니다. 함수형 컴포넌트는 단순한 자바스크립트 함수로 정의되며, 입력값을 받아들여 UI를 반환합니다.
예를들어,
import React from ‘react’;
function MyComponent(props) {
return <h1>Hello, {props.name}!</h1>;
}
이코드는 함수형 컴포넌트입니다.
props를 사용하여 부모 컴포넌트로부터 전달된 속성값에 접근할수있습니다.
useState()훅을 사용하여 컴포넌트의 내부 상태를 관리할 수 있습니다.
useEffect()훅을 사용하여 컴포넌트가 생성되거나 업데이트될때 필요한 작업을 수행할 수 있습니다.
함수형 컴포넌트는 클래스형 컴포넌트보다 더 간결하고 가독성이 높으며, 성능면에서도 우수합니다.
JSX 문법
javascript의 확장 문법으로 리액트에서 UI를 정의하는데 사용됩니다.
JSX는 javascript코드 내부에 XML형태로 작성되며, XML과 유사한 문법을 사용하여 UI를 표현합니다.
const element = <h1>Hello,world!</h1>;
이 코드는 jsx를 사용하여 h1요소를 렌더링합니다.
html과 비슷한 문법을 사용하여 리액트 어플리케이션을 작성할수 있습니다.
자바스크립트 식을 {}중괄호로 둘러싸서 jsx내부에 포함시킬수있습니다.(이를통해 동적인 ui생성가능)
jsx에서는 클래스 이름 대신 className속성을 사용합니다(jsx가 html이 아닌 자바스크립트이기 때문에)
Props / State
props:
props는 컴포넌트간에 데이터를 전달하는데 사용됩니다. 부모 컴포넌트가 자식 컴포넌트에게 속성값을 전달하면 자식 컴포넌트에서는 props를 통해 전달받은 값을 사용할 수 있습니다.
function MyComponent(props){
return <h1>hello {props.name}</h1>;
}
ReactDOM.render(<MyComponent name=”taeyoung” />, document.getElementById(’root’));
이 코드는 name이라는 props를 전달하고있습니다.
MyComponent 컴포넌트에서 props 객체를 받아서 {props.name}으로 전달된 name속성값을 출력하고 있습니다.
state:
state는 컴포넌트의 내부 상태를 관리하는데 사용됩니다. state를 사용하면 컴포넌트가 렌더링될때 동적인 ui를 생성할수있습니다.
state는 클래스형 컴포넌트에서 this.state를 통해 접근하고 this.setState()를 사용하여 업데이트 할 수 있습니다.
MyComponent클래스형 컴포넌트에서 state객체를 생성하고, count 값을 0으로 초기화합니다. handleClick()메서드를 사용하여 count값을 증가시키고, this.setState()를 호출하여 state객체를 업데이트합니다. render()메서드에서는 this.state.count값을 출력하고, 버튼 클릭시 handleClick()메서드를 호출합니다.
Virtual DOM
virtual DOM은 브라우저의 실제 DOM과 유사한 트리구조로 이루어진 객체입니다 리액트는 상태가 변경될때마다 가상의 DOM을 생성하고 이전 가상 DOM과 비교하여 변경된 부분만 실제 DOM에 반영합니다.
이것은 DOM조작이 일어날때마다 브라우저가 전체 페이지를 다시 그리는 것을 방지하여 성능을 향상시킵니다 또한 리액트는 가상 DOM의 변경사항을 최적화하여 실제 DOM조작을 최소화하도록 합니다.
Reconciliation
RECONCILIATION는 리액트에서 가상 DOM을 사용하여 업데이트를 최적화하는 과정입니다. 리액트는 상태가 변경될때마다 새로운 가상 DOM을 만들고 이전 가상 DOM과 비교하여 변경된 부분만 실제 DOM에 반영합니다 이 과정에서 RECONCILIATION이 발생합니다.
Reconciliation은 리액트에서 성능 최적화를 위한 중요한 과정 중 하나입니다. 이를 통해 불필요한 렌더링 작업을 방지하고, 빠르고 효율적인 UI 렌더링을 달성할 수 있습니다.
Event handling
이벤트 핸들링은 웹 어플리케이션에서 사용자와 상호작용할 수 있는 방법중 하나입니다. 이는 사용자의 입력에 대한 응답으로 코드를 실행하는것을 의미합니다.
버튼클릭, 마우스이동, 키보드입력등의 이벤트 처리를 할수있습니다.
리액트에서 이벤트 처리는 일반적으로 JSX문법을 사용하여 처리됩니다. JSX에서는 이벤트처리기를 props로 전달하여 구성요소에서 이벤트를 처리합니다.
import React from 'react';
function Button() {
function handleClick() {
console.log('Button clicked');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
이런식으로 버튼을 클릭할대마다 함수를 실행시킬수있습니다.
onClick prop을 사용하여 클릭 이벤트에 대한 처리기 함수인 handleClick을 전달합니다. 이벤트 처리기는 함수로 전달되며, 이벤트가 발생할 때마다 호출됩니다.
리액트 프로젝트를 실시할때에는 우선 node.js를 깐 후에 리액트 프로젝트를 실시할수있는 폴더를 만든후에 그 폴더에서 git bash를 통해 vs code를 연다 그 후에 보기에서 터미널을 눌러 열어주고 터미널에 npm init react-app .이라고 쳐준다 그 후에 프로젝트 실행 명령어인 npm run start를 누르면 프로젝트가 웹을 통해 실행되는것을 볼수이떠 그리고 웹을 끄려면 ctrl+c해주면댐
이렇게해서 보라는 버튼을 클릭했을때 곧 도착합니다 라는 경고문을 띄우게 만들수있음 굳굳!!