Hyper Text Markup Language
- <태그> <태그/> 이렇게 열고 닫는 태그 쓰거나
<br />
처럼 한번에 여닫을 수 있다.- html 의 뼈대를 구성하는 태그
<html> <head> </head> ->웹사이트가 어떤 웹사이트인지 알 수 있는 여러 속성 담고있다. (meta-data) title 등 .. <body> </body> -> 실제 웹사이트에서 보이는 컨텐츠들 </html>
보통 웹사이트는 페이지별로 html파일이 따로 존재하고, 페이지를 이동하게 될 경우 브라우저에서는 해당 페이지의 html파일을 받아와서 화면에 표시
Single Page Application
(하나의 페이지만 존재하는 웹사이트)
Cascading Style Sheets
- 웹사이트 레이아웃 등 디자인 입히는 언어
- 동적작업 처리 위한 언어
- ECMAScript 스크립트언어
- ES6 : 2015년에 표준
- 동적타이핑
- js 자료형
(타입스크립트는 자바스크립트 문법을 포함하고 변수에 각각 타입을 미리 지정해서 숫자1과 문자1 등을 비교하는 일이 없이 규칙을 좀 더 엄격히 지정한 언어라고 할 수 있다.)
A JavaScript library for building user interfaces
📚라이브러리
자주 사용되는 기능을 정리해서 모아놓은 것
ui 라이브러리는 사용자 인터페이스를 만들기 위한 기능 모음집
- 즉 리액트는
사용자와 웹사이트의 상호작용을 돕는 인터페이스를 만들기 위한 자바스크립트 기능 모음집
- 프레임워크와 라이브러리 차이 : 프로그램 흐름에 대한 제어 권한 프레임워크는 흐름의 제어 권한을 개발자가 아닌 프레임워크가 갖고있다. 반면 라이브러리는 흐름에 대한 제어를 하지 않고 개발자가 필요한 부분만 필요할 때 가져다 사용하는 형태!
라이브러리는 제어 권한이 개발자에게 있고, 프레임워크는 제어 권한이 프레임워크 자신에게 있다.📚 Virtual DOM
- 리액트의 장점 : 빠른 업데이트 & 렌더링 속도
- 리액트는 빠른 업데이트를 위해
Virtual DOM
사용, DOM 이란 Document Object Model 의 약자로 웹페이지를 정의하는 하나의 객체. 웹사이트에 대한 정보를 담고 있는 그릇
- virtual DOM은 가상의 돔이다.
화면이 업데이트 되는 것은 곧 DOM이 업데이트 된다는 말인데, 기존의 방식으로화면을 업데이트 하려면 DOM을 직접 수정해야 함= too hard- so, 리액트는 DOM을 직접 수정하는 것이 아니라 업데이트 해야할 최소한의 부분만을 찾아서 업데이트
📚 컴포넌트 기반 구조
- 컴포넌트 : 구성요소, 리액트는 모든 페이지가 컴포넌트로 되어 있고, 하나의 컴포넌트는 또 다른 여러개의 컴포넌트 조합으로 구성될 수 있다 Like 레고, 리액트 개발은 컴포넌트를 조합하여 진행.
📘 재사용성(Reusability) : 다시 사용이 가능한 성질
- 의존성과 호환성을 고려해야해
- 개발 시간이 단축된다(기존에 개발해놓은 모듈 사용 가능 하니까)
- 유지 보수가 용이하다 (버그 수정도 쉽다, 아무래도 모듈 간 의존성이 낮다는 뜻이니까)
리액트 단점 1) 방대한 학습량 2) 높은 상태관리 복잡도
자바스크립트 확장 문법 (JavaScript + XML/HTML)
예시 :const element = <h1>Hello, world!</h1>;
📘 역할
- JSX로 작성된 코드는 모두 JS코드로 변환
- 리액트는 JSX코드를 모두 createElement()함수를 사용하는 코드로 변환
📘 장점
- jsx사용시 코드가 더 간결해지고 생산성, 가독성이 올라간다,injection Attack 방어하여 보안성 올라간다
jsx 사용함
<div>Hello,{name}</div>
jsx 사용 안함
React.createElement('div',null,'Hello,${name};
📘 JSX사용법
- jsx 쓸 때에는 HTML 코드 사용하다가 중간에 JS코드 쓰고 싶으면 { } 안에 변수나 함수 써준다
- 태그의 속성(attribute)에 값 넣는 방법
- 큰 따옴표 사이에 문자열을 넣거나
const element = <div tabIndex='0'></div>
- 중괄호 사이에 자바스크립트 넣으면 됨
const element = <img src={user.avatarUrl}></img>
Elements are the smallest building blocks of React apps
리액트 앱의 가장 작은 빌딩 블록들
- 리액트 엘리먼트는 자바스크립트 객체 형태로 존재한다.
- 리액트 엘리먼트는 DOM 엘리먼트의 가상표현
📘 엘리먼트 특징
불변성 (immutable) : 엘리먼트 생성 후에는 children 이나 attribute를 바꿀 수 없다.
like 붕어빵 틀(컴포넌트)과 붕어빵(엘리먼트)
엘리먼트가 변할 수 없다면 화면 갱신이 안되는 거 아닌가요?
->화면에 변경된 엘리먼트를 보여주기 위해서는 새로운 엘리먼트를 만들어서 기존 엘리먼트와 바꿔치기 한다!📘 엘리먼트 렌더링하기
<div id="root"></div>
이
<div>
태그 안에 리액트 엘리먼트들이 렌더링되며, 이것을 Root DOM node 라고 부른다.
- 렌더링 위해 ReactDOM 의 render()라는 함수 사용 (리액트 엘리먼트를 HTML 엘리먼트에 렌더링 하는 역할)
- 렌더링 되는 과정은 Virtual DOM에서 실제DOM으로 이동하는 과정
실습 : 시계 만들기
import React from 'react'; const Clock = () => { return ( <div> <h1>안녕, 리액트!</h1> <h2>현재 시간 : {new Date().toLocaleTimeString()}</h2> </div> ); }; export default Clock;
📘 component
- 리액트는 컴포넌트 기반의 구조(component-based)
- 작은 component들이 모여서 하나의 component를 구성하고, 이러한 component들이 모여 전체 페이지를 구성한다
- 개념적으로는 JS함수와 비슷함
- 속성들을 입력으로 받아서 그에 맞는 react element를 생성하여 리턴함
📘 props
- property의 준말로 속성이라고 쓰임, props는 property가 여러개 즉, 속성들이라고 쓰인다
- 컴포넌트에 전달할 다양한 정보를 담고 있는 JS객체
props 특징
- readonly (읽기 전용)
- 리액트 컴포넌트의 props는 바꿀 수 없고, 같은 props가 들어오면 항상 같은 element를 리턴해야함
- 모든 리액트 컴포넌트는 그들의 props에 관해서는 Pure 함수 같은 역할을 해야 한다. = 모든 리액터 컴포넌트는 props를 직접 바꿀 수 없고, 같은 props에 대해서는 항상 같은 결과를 보여줘야한다!
==>React component의 props는 바꿀 수 없고 같은 props가 들어오면 항상 같은 element를 리턴해야한다.
props 사용법
- JSX 사용할 경우 컴포넌트에
key-value
쌍 형태로 넣어준다- 문자열 이외에 정수, 변수, 그리고 다른 컴포넌트 등이 들어갈 경우에는 중괄호를 이용하여 감싸준다
- JSX 사용하지 않을 경우 createElement() 함수의 두번째 parameter로 JS객체 넣어주면 된다
컴포넌트 만들기
- 컴포넌트 -
함수 컴포넌트
와클래스 컴포넌트
로 나뉜다.
- 함수 컴포넌트는 함수형식, 클래스 컴포넌트는 ES6 클래스를 사용하여 만들어진 컴포넌트
- 컴포넌트의 이름은 항당 대문자로 시작해야 한다. 리액트는 소문자로 시작하는 것은 태그로 인식
- 컴포넌트로부터 element 생성하여 이를 리액트 DOM에 전달
컴포넌트 합성
- 여러개의 컴포넌트를 합쳐서 하나의 컴포넌트를 만드는 것
//Welcome.jsx function Welcome (props) { return <h1>Hello, {props.name}</h1> } //App.js function App(props){ return( <div> <Welcome name='mike' /> <Welcome name='steve' /> <Welcome name='jane' /> </div> ) } //index.js ReactDOM.render( <App />, document.getElementById('root') );
컴포넌트 추출
- 큰 컴포넌트에서 일부를 추출하여 새로운 컴포넌트 만드는 것
- 기능 단위로 구분하는 것이 좋음, 나중에 곧바로 재사용 가능한 형태로 추출하는 것이 좋음
실습 : 댓글 컴포넌트 만들기
// Comment.jsx const Comment = (props) => { return ( //스타일은 생략 (위에있음) <div style={styles.wrapper}> <div style={styles.imageContainer}> <img src="https://upload.wikimedia.org/wikipedia/commons/ 8/89/Portrait_Placeholder.png" style={styles.image} /> </div> <div style={styles.contentContainer}> <span style={styles.nameText}>{props.name}</span> <span style={styles.commentText}>{props.comment}</span> </div> </div> ); }; export default Comment; //CommentList.jsx import Comment from './Comment'; const CommentList = (props) => { return ( <div> <Comment name='야롱' comment="나는 고양이" /> <Comment name='밤송' comment="나는 강아지" /> <Comment name='지현' comment="나는 사람" /> </div> ); }; export default CommentList; //index.js const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <CommentList /> </React.StrictMode> );
📘 State
- 리액트 컴포넌트의 변경 가능한 데이터
- 컴포넌트를 개발하는 개발자가 직접 정의해서 사용한다
- state가 변경될 경우 컴포넌트는 재렌더링됨
- 렌더링이나 데이터흐름에 사용되는 값만 state에 포함시켜야 한다 b/c 성능의 측면
state의 특징
- state는 JS의 객체
- state 를 직접적으로 변경하면 안돼
- 클래스 컴포넌트의 경우
- 생성자에서 모든 state를 한번에 정의
- state를 변경하고자 할 때에는 꼭 setState() 함수 사용해야함
- 함수 컴포넌트
- useState( ) Hook 이용하여 각각의 state 정의
- 각 state별로 주어지는 set함수를 사용하여 state값 변경
📘 생명주기
- 마운트
- 컴포넌트가 생성될 때
- componentDidMount( )
- 업데이트
- 컴포넌트의 props가 변경될 때
- setState( ) 함수 호출에 의해 state가 변경될 때
- forceUpdate( ) 라는 강제 업데이트 함수가 호출될 때
- componentDidUpdate ( )
- 언마운트
- 상위 컴포넌트에서 현재 컴포넌트를 더 이상 화면에 표시하지 않게 될 때
- componentDidUnmount( )
- 컴포넌트는 계속 존재하는 것이 아니라 시간의 흐름에 따라 생성되고 업데이트 되다가 사라지는 과정을 겪는다
실습 : 클래스 컴포넌트 만들어서 state와 생명주기 함수 사용하기
//Notification.jsx (스타일이랑 import 생략) class Notification extends React.Component { constructor(props) { super(props); this.state = {}; } componentDidMount() { console.log(`${this.props.id} componentDidMount() called.`); } componentDidUpdate() { console.log(`${this.props.id} componentDidUpdate() called.`); } componentWillUnmount() { console.log(`${this.props.id} componentWillUnmount() called.`); } render() { return ( <div style={styles.wrapper}> <span style={styles.messageText}>{this.props.message} </span> </div> ); } } export default Notification;
//NotificationList.jsx 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: [], }; } componentDidMount() { const { notifications } = this.state; timer = setInterval(() => { if (notifications.length < reservedNotifications.length) { const index = notifications.length; notifications.push(reservedNotifications[index]); this.setState({ notifications: notifications, }); } else { this.setState({ notifications: [], }); clearInterval(timer); } }, 5000); } render() { return ( <div> {this.state.notifications.map((notification) => { return ( <Notification key={notification.id} id={notification.id} message={notification.message} /> ); })} </div> ); } } export default NotificationList;
📘 훅이란?
- 리액트 state 와 생명주기 기능에 갈고리를 걸어 원하는 시점에 정해진 함수를 실행되도록 만든 것
📘 useState ( )
- state를 사용하기 위한 훅
const [변수명,set함수명]=useState(초기값);
- 변수 각각에 대해 set함수가 따로 존재한다
📘 useEffect ( )
- 사이드 이펙트를 수행하기 위한 훅 (렌더링이 끝난 이후에 실행되어야함)
- 사이드 이펙트 = 서버에서 데이터를 받아오거나 수동으로 DOM을 변경하는 등의 작업
- useEffect() 훅만으로 클래스 컴포넌트의 생명주기 함수들과 동일한 기능들 수행 가능
useEffect(이펙트함수,의존성배열);
- dependancy 따라 다르게 실행됨
useEffect(이펙트 함수, []);
=> 마운트와 언마운트시 단 한번씩만 실행됨useEffect(이펙트함수,의존성배열);
=> 의존성 배열 안에 있는 변수 중 하나라도 값이 변경되었을 때 실행됨useEffect(이펙트함수)
=> 의존성 배열 생략 시 컴포넌트가 업데이트 될 때 마다 호출됨- 선언된 컴포넌트의 props와 state에 접근할 수 있다
- useEffect( )에서 리턴하는 함수는 컴포넌트 마운트가 해제될 때 호출됨
📘 useMemo ( )
- Memoization : 최적화를 위해, 비용이 높은(연산량이 많이 드는) 함수의 호출 결과를 저장해두었다가 같은 입력값으로 함수를 호출하면 새로 함수를 호출하지 않고 이전에 저장해놨던 호출 결과를 바로 반환한다. => 결과적으로 호출 결과를 받기 까지 걸리는 시간도 짧아지고 불필요한 중복 연산도 하지 않게됨.
const memoizedValue = useMemo(값 생성 함수,의존성배열);
- 의존성 배열에 들어있는 변수가 변했을 경우에만 새로 값 생성 함수를 호출하여 결괏값을 반환
- 그렇지 않으면 기본 함수의 결과를 그대로 반환함
- 의존성 배열을 넣지 않은 경우라면 렌더링이 일어날 때마다 매번 값 생성 함수가 실행되기 때문에 의미X
- 기본구조
const memoizedValue = useMemo( () => { //연산량이 높은 작업을 수행하여 결과를 반환 return computeExpensive(의존성 변수1, 의존성 변수2); }, [의존성변수1,의존성변수2] );
- Memoized value를 리턴하는 훅 (useMemo 의 리턴값이 Memoized value 인 것!)
- useMemo( )로 전달된 함수는 렌더링이 일어나는 동안 실행됨
=> 렌더링이 일어나는 동안 실행되어서는 아 될 작업을 useMemo( ) 함수에 넣으면 안돼!📘 useCallback ( )
const memoizedValue = useMemo(값 생성 함수,의존성배열);
- useMemo()와 유사하지만 값이 아닌 함수를 반환! - 기본구조
const memoizedValue = useCallback( () => { doSomething(의존성 변수1, 의존성 변수2); }, [의존성변수1,의존성변수2] );
- 컴포넌트 내에 함수를 정의하면 매번 렌더링이 일어날 때마다 함수가 새로 정의되므로 useCallback 함수 이용하여 불필요한 함수 재정의 작업 없애는 것!
📘useRef( )
- 레퍼런스를 사용하기 위한 훅.
- 레퍼런스는 특정 컴포넌트에 접근할 수 있는 객체.
- useRef( ) 훅은 변경가능한 current라는 속성을 가진 상자.
- useRef( )을 사용하면 파라미터로 들어온 초깃값으로 초기화된 레퍼런스 객체를 반환.
📘 훅의 규칙
- Hook은 무조건 최상위 레벨에서만 호출해야한다(리액트 함수 컴포넌트)
- Hook은 컴포넌트가 렌더링 될 때마다 매번 같은 순서로 호출되어야한다
- 리액트 함수 컴포넌트에서만 Hook을 호출해야 한다
📘 커스텀Hook 만들기
for 재사용성
이렇게 중복되는 코드가 있을 경우 커스텀훅으로 만들면 좋다커스텀훅 추출하기
- 이름이 use로 시작하고 내부에서 다른 Hook을 호출하는 하나의 자바스크립트 함수
useUserStatus 는 useEffect( )를 이용하여 만든 커스텀훅
동작은 커스텀훅을 쓰기 전과 같지만 중복되는 코드가 줄었고 더 간결- 커스텀훅은 단순히 state와 연관된 로직을 재사용 가능하게 만든것, 여러개의 컴포넌트에서 하나의 커스텀훅을 사용할 때 컴포넌트 내부에 있는 모든 state와 effect는 분리되어있다.
=> 각 커스텀훅 호출에 대해 분리된 state를 얻게 된다