사용자 인터페이스를 만들기위한 자바스크립트 라이브러리
( = 사용자와 웹사이트의 상호작용을 돕는 인터페이스를 만들기위한 자바스크립트 기능모음집 )
라이브러리 :
자주 사용되는 기능들을 정리해 모아 놓은 것
사용자 인터페이스
(User Interface, UI)
흔히 보는 버튼도 인터페이스
UI 라이브러리 : 회면을 만들기 위한 기능들을 만들어 놓은 것
프레임워크 vs 라이브러리
프로그램의 흐름에 대한 제어 권한
프레임워크는 프레임워크 자신에게 있음
라이브러리는 개발자가 필요한 부분만 사용할 수 있음. 즉, 개발자에게 있음
웹사이트의 작동원리와 흐름을 함께 이해하는 것이 중요!
리액트의 장점과 단점
장점
단점
JSX란 : A Syntax extansion to JavaScript 자바스크립트의 확장 .
JacaScript + XML/HTML
const ele = <h1>hello</h1>
JSX의 역할
내부적으로 XML/ HTML 로 작성한 코드를 JS 로 변환한다.
리액트에서 JSX를 사용하는건 필수는 아니지만 JSX를 사용하면 가독성이 좋기 떄문에 편리함!
JSX 장점
JSX 사용법
XML/ HTML 을 쓰다가
자바스크립트를 쓰고 싶으면 {중괄호} 를 쓰면 됨
태그의 속성(attribute)에 값을 넣는 방법
//큰따옴표 사이에 문자열을 넣거나
const element = <div tabIndex="0"></div>;
//중괄호 사이에 자바스크립트 코드를 넣으면 된다
const element = <img src={user.avatarUrl}></img>;
자식 (children) 을 정의하는 방법
const element = (
<div>
<h1>자식을 정의하는 방법</h1>
<h2>JSX 신기해</h2>
</div>
)
Element 란? 어떤 물체를 구성하는 성분
React Elements 란 리액트를 구성하는 가장 작은 요소.
'Elemnets are the smallest buliding blocks of React apps'
리액트 엘리먼트는 돔 엘리먼트의 가상 표현이라 보면 된다.
화면에서 보여지는 것을 기술.
자바스크입트 객체 형태로 존재
type: "button",
props: {
classNace: "bg-green",
children: {
type: "b",
props: {
children: "Hello, element",
},
},
}
위 엘리먼트가 실제로 랜더링 된다면 아래와 같은 돔 엘리먼트가 된다
<button class="bg-green">
<b>
Hello, element!
</b>
</button>
컴포넌트는 엘리먼트의 속성들은 아래 코드와 같다.
React.createElement(
type,
[props],
[...children]
)
컴포넌트 rendering 위해 모든 컴포넌트가 createElement 를 통해 엘리먼트로 변환된다는 것을 기억하자!
우리 눈에 보이는 것을 기술한다고 햇는데 element가 불변하다면 화면갱신이 안되는 것 아닌가?
'한 번 elements 생성 후에는 children 이나 attributes를 바꿀 수 없다.' 를 다시 보면
붕어빵을 예로 들면 component 는 붕어빵 틀, element는 붕어빵이다.
구워져 나온 붕어빵은 엘리먼트 생성이 끝난거이기 때문에 바꿀 수 없는거라고 생각하면 쉽다.
구워져 나오는 과정은 엘리먼트를 생성하는 것.
그렇다면 화면에 변경된 엘리먼트를 보여주기 위해서는??
=> 기존의 엘리먼트를 변경하는 것이 아니라 새로운 엘리먼트를 만들어 기존의 엘리먼트와 바꿔침
Root DOM Node
<div id="root"></div>
root div 에 실제로 렌더링 하기 위해 아래 코드처럼 작성한다.
const element = <h1>안녕</h1>;
ReactDOM.render(element, document.querySelector('#root'));
이 코드는 먼저 엘리먼트를 생성하고 생성된 엘리먼트를 root 에 렌더링 하는 코드.
렌더링 위해 ReactDOM.render
을 사용 =>
첫번째 parameter 에 있는 react element를 두번째 parameter의 Html 엘리먼트, 즉 DOM element에 렌더링 하는 역할을 한다.
여기서 한번 더 짚고 넘어가자면 react element는 리액트 버츄얼 돔에 있고 DOM 엘리먼트는 실제 브라우저의 돔에 존재한다.
렌더링 한다는 말이 리액트 버추얼 돔에서 실제 돔으로 이동하는 과정이라고 할 수 있다.
엘리먼트는 불변성을 갖고 있기 때문에 엘리먼트를 업데이트 하기 위해서는 다시 생성해야 한다.
function tick() {
const element = (
<div>
<h1>hi</h1>
<h2>what time? {new Date().toLocaleTimeString()}</h2>
</div>
);
ReactDOM.render(element, document.querySelector("#root"));
}
setInterval(tick, 1000);
이해될때까지 연습하기
리액트 컴포넌트는
작은 컴포넌트가 모여 하나의 컴포넌트를 구성하고 또 이런 컴포넌트들이 모여서 전체 페이지를 구성한다.
이랙트 컴포넌트를 하나의 함수 라고 생각해도 된다.
근데 입려과 출력이 자바스크립트의 함수와 다르다 .
자바스크립트 객체 형태로 존재.
: 컴포넌트에 전달할 다양한 정보를 담고있는 자바스크립트 객체
리액트 컴포넌트의 입력으로 들어감 .
Property 를 줄여서 prop이라고 한다.
property 는 사전적으로 속성 이라는 뜻이다.
무엇의 속성? => component의 속성
붕어빵으로 생각하면 이해가 쉬움.
같은 리액트 컴포넌트에서 눈에 보이는 글자는 색 바꿔줄 수 있는 재료 라고 생각하기
네가지 다 같은 컴포넌트로 생성되었지만, 그 속성이 다름을 볼 수 있는데 그걸 Props를 이용해서 바꿔주는 것이다 .
Props는 Read-Only 이다.
읽을 수만 있다 = 값을 변경 할 수 없다.
(마치 붕어빵을 다 구웠는데, 속재료를 바꿀 수 없음을 생각하면 된다,.)
그럼 값을 바꿔주고 싶다면? => 새 element를 생성!
모든 리액트 컴포넌트는 그들의 Props에 관해서는 Pure 함수같은 역할을 해야 한다.
Pure 함수란? 같은 입력값에 대해 항상 같은 결과값을 보여주는 함수
function add(a,b) { return a+b }
이해하기 쉽게 말하면!
모든 리액트 컴포넌트는 Props를 직접 바꿀 수 없고, 같은 Props에 대해서는
항상 같은 결과(react element)를 return 할 것이라는 말이다.
function App(props) {
return <Profile name="수"
introduction="hi i'm su"
viewCount={1000} />;
}
이렇게 하면 이 속성의 값들이 모두 profile 컴포넌트의 Props로 전달되며
Props 함수는 아래와 같은 자바스크립트 객체가 된다.
{
name:'수',
introduction : "hi i'm su",
viewCount : 1000
}
중괄호를 사용해서 props값에 컴포넌트도 넣어줄 수 있다.
function App(props) {
return (
<Layout
width={2560}
height={1000}
header={<Header title="리액트연습중" />}
footer={<Footer />}
/>
);
}
jsx 를 사용하는 경우 간단하게 컴포넌트에 props 를 넣을 수 있다.
컴포넌트는 Function Component / Class Component 가 있다.
Class Component가 불편해서 만든게 Function Component 이고, 함수 컴포넌트를 개선해서 만든게 Hook 이다.
모든 리액트 컴포넌트는 pure 한 역할을 해야 한다.
이 말은 결국 리액트 컴포넌트를 하나의 함수 라고 생각해야 한다는 말이다
이 코드를 보면
function Welcome(props) {
return <h1>안녕, {props.name}</h1>
}
하나의 props 를 받아서 하나의 리액트 엘리먼트를 리턴하기 떄문에 리액트 컴포넌트라고 볼 수 있다.
그리고 이런 형태를 함수 컴포넌트라고 할 수 있다.
함수컴포넌트와의 가장 큰 차이점은, 리액트의 모든 클래스 컴포넌트는 React.Component를 상속받아 만든다.
위 함수형 컴포넌트의 코드와 동일한데, Class 컴포넌트를 이용하면 이렇게 작성해야 한다.
class Welcome extends React.Component {
render() {
return <h1>안녕, {this.props.name}</h1>;
}
}
예를 들면
const element = <div/>
이렇게 작성하면 HTML div 태그로 인식하고
대문자로 작성을 하면,
const element = <Welcome name="수수"/> ;
Welcome 이라는 리액트 Component 로 인식한다.
DOM 태그를 사용한 element
const element = <div/>
사용자가 정의한 Component를 사용한 element
const element = <Welcome name="수수"/> ;
이걸 렌더링하기 위한 실제 코드
function Welcome(props) {
return <h1>안녕,{props.name}</h1>;
}
const element = <Welcome name="쑤" />;
ReactDOM.render(element,
document.querySelector("#root")
);
Component 안에 또 다른 Component를 쓸 수 있다
복잡한 화면을 여러개의 Component로 나눠서 구현이 가능하다
function App(props) {
return (
<div>
<Welcome name="Mike" />
<Welcome name="Steve" />
<Welcome name="Jane" />
</div>
);
}
Welcome 컴포넌트로 컴포넌트 합성을 하는 코드이다.
Props의 값을 다르게 해서 Welcome 컴포넌트를 여러개 쓰고 있음.
여러개의 컴포넌트를 합쳐서 App 컴포넌트를 만들었음.
큰 컴포넌트를 쪼갬!
재사용성 up 개발속도 up
function Avatar(props) {
return (
<img
className="avatar"
src="{props.user.avatarUrl}"
alt="{props.user.name}"
/>
);
}
이렇게 Avartar 컴포넌트를 추출했으니, 다시 Comment 컴포넌트에 넣어야한다.
function UserInfo(props) {
return (
<div className="user-info">
<Avatar user={props.user} />
<div className="user-info-name">{props.user.name}</div>
</div>
);
}
위에서 만든 Avatar 컴포넌트도 같이 추출
Comment 컴포넌트는 이렇게 변하고
그림으로 살펴보면 이렇게 된다.
state 는 이해될 때까지 공부하기
state : 상태 , react component의 변경가능한 데이터
사전에 정해져 있는게 아니라 개발자가 정의한다.
state 를 정의할 때 중요한 점은
렌더링이나 데이터 흐름에 사용되는 값만 state 에 포함시켜야 함!
왜냐면 state 가 변경 될 경우 컴포넌트가 재렌더링되기 때문에 렌더링과 데이터흐름에 관련없는 값을 포함하면 불필요한 경우에 컴포넌트가 재실행 => 성능저하로 이어짐
state 는
// state를 직접 수정 (잘못된 사용범)
this.state = {
name: "su",
};
// setstate 함수를 통한 수정 (정상적인 사용법)
this.setState({
name: "su",
});
꼭 setState 를 통해 변경해야 함 !
Component 가 계속 존재하는 것이 아니라,
시간의 흐름에 따라 생성되고 업데이트 되다가 사라진다.
상위컴포에서 하위 컴포를 사용하지 않을때 Unmounting 이 된다.
Notifiaction 에서 눈여겨봐야할 부분은 state 선언이다.
처음 생성된 notifications 라는 빈 배열을 state 에 넣어줬다.
이처럼 생성자에서는 앞으로 사용할 데이터를 state 에 넣어서 초기화 한다!
import React from "react";
import Notification from "./Notification";
const reservedNotifications = [
{
message: "안녕하새요, 오늘 일정을 알려드립니다.",
},
{
message: "점심식사 시간입니다",
},
{
message: "이제 곧 미팅이 시작됩니다.",
},
];
let timer;
class NotificationList extends React.Component {
constructor(props) {
super(props);
this.state = {
notifications: [],
};
}
componentDisMount() {
const { notifications } = this.state;
timer = setInterval(() => {
if (notifications.length < reservedNotifications.length) {
const index = notifications.length;
notifications.push(reservedNotifications[index]);
this.setState({
notifications: notifications,
});
} else {
clearInterval(timer);
}
}, 1000);
}
render() {
return (
<div>
{this.state.notifications.map((notification) => {
return <Notification message={notification.message} />;
})}
</div>
);
}
}
export default NotificationList;
클래스 컴포넌트의 생명주기 함수 중 하나인 componentDidMount
함수는 자바스크립트의 setInterval
함수를 사용하여 매 1000ms 마다 정해진 작업을 수행하고 있다.
이 작업은 미리 만들어 둔 알림 데이터(reservedNotifications)로부터
데이터를 하나씩 가져와서 state 에 있는 notifications 에 넣고 업데이트 하는 것
주의해야 할 부분은
setState 를 사용했다는 것!
즉, Class Component 에서 상태를 업데이트 하기 위해서는 반드시 setState를 사용해야 한다.
참고 및 출처 : 인프런 처음만난 리액트