React 특강-1 by soaple

지현·2022년 7월 28일
1

React

목록 보기
5/11
post-thumbnail

💻리액트 학습 전 기초지식

HTML

  • Hyper Text Markup Language
  • <태그> <태그/> 이렇게 열고 닫는 태그 쓰거나 <br /> 처럼 한번에 여닫을 수 있다.
  • html 의 뼈대를 구성하는 태그
<html>
	<head>
    </head> ->웹사이트가 어떤 웹사이트인지 알 수 있는 여러 속성 담고있다.
    (meta-data) title 등 .. 
    <body>
    </body> -> 실제 웹사이트에서 보이는 컨텐츠들
</html>

보통 웹사이트는 페이지별로 html파일이 따로 존재하고, 페이지를 이동하게 될 경우 브라우저에서는 해당 페이지의 html파일을 받아와서 화면에 표시

SPA

  • Single Page Application (하나의 페이지만 존재하는 웹사이트)

css

  • Cascading Style Sheets
  • 웹사이트 레이아웃 등 디자인 입히는 언어

JavaScript

  • 동적작업 처리 위한 언어
  • 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) 높은 상태관리 복잡도

📚 JSX

자바스크립트 확장 문법 (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>

📚 Element

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와 Props

📘 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가 변경될 경우 컴포넌트는 재렌더링됨
  • 렌더링이나 데이터흐름에 사용되는 값만 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;

📚 HOOK

📘 훅이란?

  • 리액트 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를 얻게 된다

0개의 댓글