본문 바로가기

WINK-(Web & App)/React.js 스터디

[2024 여름방학 React.js 스터디] 이종윤 #3주차

반응형

DOM(Document Object Model)이란

: 문서 객체 모델이라는 뜻, 스크립트언어로 html문서를 제어할 수 있도록 웹 문서를 객체화 한 것이다.

: 즉 html문서에 있는  tree구조라는 모양으로 태그와 태그안에 텍스트와 속성들을 모두 객체화 해서 js에서 편집 할 수 있도록 만들어주는 것이다.

이렇게...

리액트가 만들어진 이유

원래 JavaScript를 사용하여 HTML 로 구성한 UI 를 제어하기 위해서는 브라우저의 DOM Selector API 를 사용해서 특정 DOM 을 선택한뒤 특정한 이벤트가 발생하면 변화를 주도록 설정해야한다.

그런데 이렇게 dom을 하나하나 찝어가면서 업데이트를 하다가 처리해야 할 이벤트도 다양해지고, 관리해야 할 상태값도 다양해지고, DOM 도 다양해지게 된다면, 이에 따라 업데이트를 하는 규칙도 많이 복잡해지기 때문에, 조금 과장을 많이 하자면 코드가 다음과 같은 형태가 된다.

기존에 문제

그래서, Ember, Backbone, AngularJS 등의 프레임워크들과 같이 자바스크립트의 특정 값이 바뀌면 특정 DOM의 속성이 바뀌도록 연결을 해주어서, 업데이트 하는 작업을 간소화해주는 방식으로 웹개발의 어려움을 해결해주었다.

그런데 React는 조금 다르다.

리액트는 "어떠한 상태가 바뀌었을때, 그 상태에 따라 DOM 을 어떻게 업데이트 할 지 규칙을 정하는 것이 아니라, 아예 다 날려버리고 처음부터 모든걸 새로 만들어서 보여준다면 어떨까?" 라는 아이디어에서 개발이 시작되었다.

그러면 "업데이트를 어떻게 해야 할 지" 에 대한 고민을 전혀 안해도 되기 때문에 개발이 정말 쉬워질 것이다.

하지만, 정말로 동적인 UI 를 보여주기 위해서 모든걸 다 날려버리고 모든걸 새로 만들게 된다면, 속도가 굉장히 느릴 것이다.

하지만, 리액트에서는 Virtual DOM 이라는 것을 사용해서 이를 가능하게 했다.

랜더링 순서

우선 랜더링은 위 그림처럼 크게 5단계로 이뤄진다.

불러오기 -> DOM, COSSOM 구축 -> 랜더트리(DOM + COSSOM) 생성 -> layout -> paint

1. 불러오기
: 로더(Loader)가 서버로부터 전달받은 리소스 스트림을 읽는 과정

2. DOM, CSSOM 생성
웹 엔진의 HTML/XML 파서가 문서를 파싱해 DOM Tree를, CSS 파서가 CSSOM 트리를 생성

3. 생성된 DOM과 CSSOM으로 렌더링 트리 생성
DOM Tree + CSSOM Tree, 렌더링에 필효한 노드만 선택해 페이지를 렌더링하는데 사용

4. 레이아웃
: 렌더트리를 토대로 그려질 노드와 스타일, 크기를 계산
렌더링 트리에서 위치, 크기등을 알 수 없기 때문에 객체들에게 위치 크기 등을 정해주는 과정, css는 선택자에 따라서 적용되는 태그가 다르기 때문에 모든 css 스타일을 분석해 태그에 스타일 규칙이 적용되게 결정

5. 그리기
: 렌더트리의 각 노드를 실제 픽셀로 변환, 실제로 그리는 작업을 실행

 

여기서 기존에는 DOM에 어떠한 변화가 나타나면 랜더트리가 그때마다 재생성된다.

이 과정은 너무 오래걸리고 비효율적이다.

그래서 새로 고안된 방안이 Vitural DOM이다.

Vitural DOM

: 간단히 말해 진짜 DOM의 복사본이다.

이 virtural DOM은 실제DOM과 같은 속성들을 가지지만 실제DOM이 가지는 api를 가지고 있지는 않다.

그러므로  virtural DOM은 새로운 UI를 랜더링하는데 실제DOM보다 훨씬 빠르다.

그리고 virtural DOM에 새로운 UI를 랜더링하고 실제DOM과 다른 점만 비교하여 적용시키면 되니 훨씬 효율적인 프로세스이다.

virtural DOM 작동방식커컴포넌트

컴포넌트

: UI를 구성하는 UI요소이다. (UI는 user interface의 약자, 사용자 인터페이스, 유저 눈에 보이는 '디자인'적인 요소)

컴포넌트 예시

위 그림처럼 웹을 컴포넌트 단위로 나눌 수 있다.

이렇게 컴포넌트 단위로 나눠서 개발을 하면 위 그림 처럼 개발 한 것을 여러 번 재 활용 할 수 있고 유지보수 할 때 컴포넌트 단위로 수정하니 더욱 용이하다. 그리고 다른 개발자들과 공유할 때 더 알아보기 편리해서 생산성 또한 올라갈 수 있다.

const jongyun = (a) => {
	console.log('jjang');
    return a + 10;
    };
    
export default jongyun;

 

위 코드처럼 함수 단위로 작성한 컴포넌트를 이전에 배운 자바스크립트 묘듈화 기능으로 보내고 가지고 오고 하며 쓸 수 있다. (또한 컴포넌트는 클래스로도 작성 될 수 있다.)

import와 export

JSX문법

: JSX(Syntax Extension to Javascript) 는 리액트에서 생김새를 정의할 때, 사용하는 문법이다.

: 자바스크립트와 XML.HTML을 합친 것이라고 볼 수 있다

 

1. 태그를 열면 꼭 닫기 : 즉 <div>같은 것으로 태그를 열면 꼭 </div>로 태그를 닫아주어야 한다.

2. Self Closing 태그 :  <Hello /> 처럼 Hello 컴포넌트를 사용 할 때 스스로 닫느 태그를 사용할 수 있다.

3. 두개 이상의 태그는 꼭 감싸기

 

<Hello />
<div>안녕히계세요.</div>       이렇게 쓰면 안된다.

 

<div>
     <Hello />
     <div>안녕히계세요.</div>
</div>                                      이렇게 꼭 감싸줘야한다.

 

4. 리액트의 Fragment : 3번에서 쓰인 감싸는 <div>를 사용하기 여의치 않을 때 <></>로 묶어줄 수 있다.

5. JSX 안에 자바스크립트 값 사용하기: {} 으로 감싸서 보여주면 된다.

6. JSX안에서의 style : 인라인 스타일은 객체 형태로 작성을 해야 하며, background-color 처럼 - 로 구분되어 있는 이름들은 backgroundColor 처럼 camelCase 형태로 네이밍 해주어야 한다.

7. JSX안에서의 className : CSS class 를 설정 할 때에는 class= 가 아닌 className= 으로 설정해야 한다.

8. 주석: JSX 내부의 주석은 '{/* ~~ */}' 작성한다. 또한 열리는 태그 내부에서는 '// ~~' 도 주석 작성이 가능

props

: props(properties)는 우리가 어떠한 값을 컴포넌트에게 전달해줘야 할 때 사용하는 것이다.

- props는 반드시 위에서 아래(부모에서 자식)방향으로만 흐른다(단방향 메커니즘)

- props는 반드시 읽기 전용이며, 자식 컴포넌트에선 변경할 수 없다.

 

<props 사용>

import React from 'react';

function Hello(props) {
  return <div>안녕하세요 {props.name}</div>
}

export default Hello;
import React from 'react';
import Hello from './Hello'; // Hello 컴포넌트를 임포트

function App() {
  return (
    <div>
      <Hello name="철수" />
      <Hello name="영희" />
    </div>
  );
}

export default App;

으로 사용할 수가 있다.

 

위 코드에서 props.name이 쓰인 것처럼 props 내부의 값을 조회 할 때마다 props.을 사용해야한다.

함수의 파라미터에서 비구조화 할당 (혹은 구조 분해라고도 불립니다) 문법을 사용하면 조금 더 코드를 간결하게 작성 할 수 있다.

import React from 'react';

function Hello({ name }) {
  return <div>안녕하세요 {name}</div>
}

export default Hello;

이렇게

defaultProps

: 컴포넌트에 props 를 지정하지 않았을 때 기본적으로 사용 할 값을 설정하는 것이다.

Hello.defaultProps = {
  name: '이름없음'
}

위 코드에 이 코드만 추가해주면 된다.

props.children

: A 컴포넌트 사이에 B 컴포넌트가 있을 때, A 컴포넌트에서 B 컴포넌트 내용을 보여주려고 사용하는 props이다.

 

- children이라는 개념: React는 JSX라는 문법을 채택하여 사용하고 있다. JSX는 html과 유사한 문법으로 꺽쇠 사이에 타입과 속성을 부여해 프로젝트 구조를 짜는 목적으로 사용된다. 이러한 컴포넌트들 사이에는 포함관계를 설정할 수 있는데, 이때 상위 컴포넌트를 parent component, 하위 컴포넌트를 child component라고 부른다. 그리고 부모-자식 관계가 설정되면 부모 컴포넌트 내부에서는 children prop을 통해 자식 컴포넌트 정보에 접근할 수 있다.

<ParentComponent>
	<ChildComponent/>
</ParantComponent>
const ParantComponent =(props) =>{
	return <>
    	{props.children}
    </>
}

이렇게 쓰면 된다.

조건부 렌더링

: 조건부 렌더링이란, 특정 조건에 따라 다른 결과물을 렌더링 하는 것을 의미한다.

 

* 조건 삼항 연산자 : 조건 (삼항) 연산자는 JavaScript에서 세 개의 피연산자를 받는 유일한 연산자이다. 앞에서부터 조건문, 물음표(?), 조건문이 참일 경우 실행할 표현식, 콜론(:), 조건문이 거짓일 경우 실행할 표현식이 배치된다.

단축 평가 (short-circuit evaluation) 논리 계산법

- 컴포넌트의 props 값을 설정하게 될 때 만약 props 이름만 작성하고 값 설정을 생략한다면, 이를 true 로 설정한 것으로 간주한다.

useState

: useState는 리액트의 Hooks 중 하나로 함수형 컴포넌트에서도 상태를 관리할 수 있는 함수이다.

usestate는 값을 반환을 하는 데 2개의 값을 항상 동시에 반환한다.

그 두 개의 값은 항상 [현재 state, state 를 변경하기 위한 함수] 이다.

우리는 이것을 대부분

const [fooBar, setFooBar] = useState()

이렇게 받아서 쓴다.

즉, fooBar 이 state 그 자체인 것이고, setFooBar 은 이 state 를 변경할 때 사용하는 함수인 것이다.

input

: 리액트에서 사용자가 입력 할 수 있는 태그이다.

import React from 'react';

function App() {
  return (
    <InputSample />
  );
}

function InputSample() {
  return (
    <div>
      <input />
      <button>초기화</button>
      <div>
        <b>값: </b>
      </div>
    </div>
  );
}

export default InputSample;
export default App;

 

이번에도 useState 를 사용한다.

이번에는 input 의 onChange 라는 이벤트를 사용하는데 이벤트에 등록하는 함수에서는 이벤트 객체 e 를 파라미터로 받아와서 사용 할 수 있는데 이 객체의 e.target 은 이벤트가 발생한 DOM 인 input DOM 을 가르키게된다.

이 DOM 의 value 값, 즉 e.target.value 를 조회하면 현재 input 에 입력한 값이 무엇인지 알 수 있다.

이 값을 useState 를 통해서 관리를 해주면 된다.

import React, { useState } from 'react';

function InputSample() {
  const [text, setText] = useState('');

  const onChange = (e) => {
    setText(e.target.value);
  };

  const onReset = () => {
    setText('');
  };

  return (
    <div>
      <input onChange={onChange} value={text}  />
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: {text}</b>
      </div>
    </div>
  );
}

export default InputSample;

이렇게 ;;

여러개의 input 상태 관리

- placeholder  : input 이 비어져있을 때 인풋에 대한 설명을 보여준다.

 

input 의 개수가 여러개가 됐을때는, 단순히 useState 를 여러번 사용하고 onChange 도 여러개 만들어서 구현 할 수 있다. 하지만 그 방법은 가장 좋은 방법은 아니다.

더 좋은 방법은, input 에 name 을 설정하고 이벤트가 발생했을 때 이 값을 참조하는 것이다.

그리고, useState 에서는 문자열이 아니라 객체 형태의 상태를 관리해주어야 한다.

import React, { useState } from 'react';

function InputSample() {
  const [inputs, setInputs] = useState({
    name: '',
    nickname: ''
  });

  const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출

  const onChange = (e) => {
    const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
    setInputs({
      ...inputs, // 기존의 input 객체를 복사한 뒤
      [name]: value // name 키를 가진 값을 value 로 설정
    });
  };

  const onReset = () => {
    setInputs({
      name: '',
      nickname: '',
    })
  };


  return (
    <div>
      <input name="name" placeholder="이름" onChange={onChange} value={name} />
      <input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
      <button onClick={onReset}>초기화</button>
      <div>
        <b>값: </b>
        {name} ({nickname})
      </div>
    </div>
  );
}

export default InputSample;

이렇게 ;;

반응형