ㅇㅇㅈ Blog

프론트엔드 수행중

0%

React 기초

React

  • 유저 인터페이스를 만들기위한 자바스크립트 라이브러리(library)
  • Component based Development

Component

Component Tree => DOM Tree

  • DOM과는 다르게 Component 내장되어 있는 태그들을 조합하고 스타일,동작등을 한 번에 다루는 형태를 만든 다음 재활용하는 방식

Virtual DOM ?

  • DOM을 직접 제어하는 경우
    • 바뀐 부분만 정확히 바꿔야 한다.
  • DOM을 직접 제어하지 않는 경우
    • 가상의 돔 트리를 사용해서 이정 상태와 이후 상태를 비교하여, 바뀐 부분을 찾아내서 자동으로 바꾼다

CSR(React Client Side Rendering)

  • JS가 전부 다운로드 되어 리액트 애플리케이션이 정상 실행되기 전까지는 화면이 보이지 않음.
  • JS가 전부 다운로드 되어 리액트 애플리케이션이 정상 실행된 후, 화면이 보이면서 유저가 인터렉션 가능

SSR(React Server Side Rendering)

  • JS가 전부 다운로드 되지 않아도, 일단 화면은 보이지만 유저가 사용 할 수 없음.
  • JS가 전부 다운로드 되어 리액트 애플리케이션이 정상 실행된 후, 유저가 사용 가능

리액트가 하는 일

리액트의 핵심 모듈 2개로 리액트가 하는 일 알아보기

만들어진 리액트 컴포넌트를 실제 HTMLElement에 연결할 때 ReactDOM 라이브러리를 이용한다

1
2
3
4
5
// 1. 리액트 컴포넌트 => HTMLElement 연결하기
import ReactDOM from 'react-dom'

// 2. 리액트 컴포넌트 만들기
import React from 'react'

Hooks 이전

Hook이라는 기술이 나오기 전까지와 나온 후의 컴포넌트 작성법의 기준이 다르다

  • 컴포넌트 내부에 상태가 있다면?
    • class
  • 컴포넌트 내부에 상태가 없다면?
    • 라이프사이클을 사용해야 한다면?
      • class
    • 라이프사이클에 관계 없다면?
      • function

Hooks 이후

  • class
    • React안의 Component 클래스를 상속받아 사용한다
    • render() 함수를 사용해야 한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react'

// 정의
class ClassComponent extends React.Component {
// React안의 Component 클래스를 상속 받는다
render() {
// class 컴포넌트는 render() 메소드를 꼭 정의 해야 한다
return <div>Hello</div>
}
}
/* prettier-ignore */
// 사용
ReactDOM.render( // 첫번째인자 <컴포넌트>, 두번째 사용될 곳
<ClassComponent />,
document.querySelector('#root')
)
  • function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react'

// 정의 1
function FunctionComponent(){
return <div>Hello</div>

// 정의 2
const FunctionComponent = () => <div>Hello</div>

// 사용
ReactDOM.render(
<FunctionComponent />,
document.querySelector('#root')
)

React.createElement로 컴포넌트 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
React.createElement(
첫 번째 인자 : type, // 태그 이름 문자열 | 리액트 컴포넌트 | React.Fragment,
두 번째 인자 : [props], // 리액트 컴포넌트에 넣어주는 데이터 객체
세 번째 인자 : [...children] // 자식으로 넣어주는 요소들 (여러개 가능)
)

// type 1. 태그 이름 문자열
ReactDOM.render(
React.createElement( // React.createElement = Component생성
'h1',
null,
'`type 이 "태그 이름 문자열" 입니다.`'
),
document.querySelector('#root')
)

// type 2. 리액트 컴포넌트
const Component = () => { // 컴포넌트 생성
return React.createElement(
'p',
'null',
`type 이 "React 컴포넌트" 입니다.`
)
}
ReactDOM.render(
React.createElement(Component,null,null), // 첫 번째 인자로 컴포넌트를 넣어준다
document.querySelector('#root')
)

// type 3. React.Fragment
ReactDOM.render(
React.createElement(
React.Fragment,
null,
`type이 "React Fragment" 입니다.`
`type이 "React Fragment" 입니다.`
`type이 "React Fragment" 입니다.`
),
document.querySelector('#root')
)

// 4. 복잡한 리액트 엘리먼트 모임
// createElement로 만들기에는 어려움이 있다
ReactDOM.render(
React.createElement(
'div',
null,
React.createElement(
'div',
null,
React.createElement('h1', null, '주제'),
React.createElement(
'ul',
null,
React.createElement('li', null, 'React'),
React.createElement('li', null, 'vue')
)
)
),
document.querySelector('#root')
)

JSX 문법으로 작성된 코드는 순수한 JavaScript로 컴파일 하여 사용한다.
=> babel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ReactDOM.render(
<div a='a'>
// Type부분
<div>
// children 부분
<h1>주제</h1>
<ul>
<li>React</li>
<li>Vue</li>
</ul>
</div>
</div>,
document.querySelector('#root')
)
// babel로 순수한 Javascript로 컴파일 해준다

JSX

  • 가독성이 좋다
  • babel과 같은 컴파일 과정에서 문법적 오류를 인지하기 쉬움

JSX 문법

  • 최상위 요소가 하나여야 한다.
  • 최상위 요소 리턴하는 경우, ()로 감싸야 한다
  • 자식들을 바로 렌더링 하고 싶으면,<>자식들</>를 사용한다 => Fragment
1
2
3
4
5
6
7
8
9
10
11
12
ReactDOM.render(
<>
// 최상위 요소로 사용 할 수 있다
<div>
<div>주제</div>
</div>
<div>
<div>제목</div>
</div>
</>,
document.querySelector('#root')
)
  • 자바스크립트 표현식을 사용하려면, {표현식}을 이용한다
1
2
3
4
5
6
7
const title = '주제'
ReactDOM.render(
<div>
<div>{title}</div>
</div>,
document.querySelector('#root')
)
  • if 문은 사용할 수 없다
    • 삼항연산자 혹은 &&을 사용한다
  • style을 이용해 인라인 스타일링이 가능하다
  • class 대신 className을 사용해 class를 적용할 수 있다
  • 자식요소가 있으면, 꼭 닫아야 하고, 자식요소가 없으면 열면서 닫아야 한다
    • <p>hello</p>
    • <br/>

Props와 State

  • Props는 컴포넌트 외부에서 컴포넌트에게 주는 데이터.
  • State는 컴포넌트 내부에서 변경할 수 있는 데이터.
  • 둘 다 변경이 발생하면, 렌더가 다시 일어날 수 있다

Render 함수

  • Props와 State를 바탕으로 컴포넌트를 그린다
  • Props와 State가 변경되면, 컴포넌트를 다시 그린다
  • 컴포넌트를 그리는 방법을 기술하는 함수가 렌더 함수

Props

함수로 만든 컴포넌트

  • props는 컴포넌트의 인자로 받는다
1
2
3
4
5
6
7
8
9
10
11
12
// {message: '안녕하세요'}의 형태로 props에 들어오게 된다.
function Component(props) {
return (
<div>
<h1>{props.message} 이것은 함수로 만든 컴포넌트 입니다.</h1>
</div>
)
}
ReactDOM.render(
<Component message='안녕하세요' />,
document.querySelector('#root')
)

클래스로 만든 컴포넌트

  • 클래스 컴포넌트에서는 this로 props를 받는다
1
2
3
4
5
6
7
8
9
10
11
12
13
class Component extends React.Component {
render() {
return (
<div>
<h1>{this.props.message} 이것은 클래스로 만든 컴포넌트 입니다.</h1>
</div>
)
}
}
ReactDOM.render(
<Component message='안녕하세요!!' />,
document.querySelector('#root')
)

defaultProps

  • props의 기본값을 쓰고 싶을때
  • 직접 지정하면 지정한 값이 들어간다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Component extends React.Component {
render() {
return (
<div>
<h1>{this.props.message} 이것은 클래스로 만든 컴포넌트 입니다.</h1>
</div>
)
}
static defaultProps = {
// 클래스 문법을 이용한 방법
message: '클래스 컴포넌트에서만 쓸수있다',
}
}
Component.defaultProps = {
// 클래스 컴포넌트 와 함수 컴포넌트 모두 사용 할 수 있다
message: '기본값',
}
ReactDOM.render(<Component />, document.querySelector('#root'))

State

  • state는 객체여야한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 클래스 컴포넌트에서 state 사용법
class Component extends React.Component {
// 방법 1
state = {
count: 0,
}

// 방법 2
constructor(props) {
super(props)
this.state = {
count: 0,
}
}
render() {
return (
<div>
<h1>{this.props.message} 이것은 클래스로 만든 컴포넌트 입니다.</h1>
</div>
)
}
}

Event Hnadling

  • HTML DOM에 클릭하면 이벤트가 발생하고, 발생하면 그에 맞는 변경이 일어나도록 해야한다
  • JSX에 이벤트를 설정할 수 있다.
  • camelCase 로만 사용할 수 있다
    • onClick, onMouseEnter
  • 이벤트에 연결된 자바스크립트 코드는 함수이다
    • 이벤트 = {함수}와 같이 쓴다
  • 실제 DOM 요소들에만 사용 가능하다
    • 리액트 컴포넌트에 사용하면, 그냥 Props로 전달한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 인라인으로 이벤트 핸들링
class Comp extends React.Component {
state = {
count: 0,
}
render() {
return (
<div>
<p>{this.state.count}</p>
<button
onClick={() => {
// camelCase로 이벤트 작성해줘야 한다
this.setState((state) => ({
...state,
count: state.count + 1,
}))
}}
>
클릭
</button>
</div>
)
}
}
ReactDOM.render(<Comp />, document.querySelector('#root'))

// 메소드를 따로 빼줬을때
class Comp extends React.Component {
state = {
count: 0,
}
render() {
return (
<div>
<p>{this.state.count}</p>
<button onClick={this.click}>클릭</button>
</div>
)
}
click = () => {
this.setState((state) => ({
...state,
count: state.count + 1,
}))
}
}
ReactDOM.render(<Comp />, document.querySelector('#root'))

Component Lifecycle

리액트 컴포넌트는 탄생부터 죽음까지 여러지점에서 개발자가 작업이 가능하도록 메서드를 오버라이딩 할 수 있게 해준다.
v16.3 이전과 이후로 몇 개의 메서드가 이름이 달라졌다

Initialization

- setup props and state

Mounting

1. v16.3 이전: componentWillMount => v16.3 이후: static getDerivedStateFromProps(nextProps, prevState),
2. render (최초로 브라우저에 그려짐)
3. componentDidMount

Updation - props가 바뀌거나 state가 바뀌는 것

  • props

      1. v16.3 이전: componentWillReceiveProps - props일 경우에만 붙는다  => v16.3 이후: getDerivedStateFromProps
      2. shouldComponentUpdate - 컴포넌트가 업데이트 되어야 하는지 아닌지 결정하는 구간 true,false, 불필요하게 렌더되는걸 방지하기 위해 필요하다
      3. v16.3 이전: componentWillUpdate =>  v16.3 이후: getSnapshotBeforeUpdate
      4. render
      5. componentDidUpdate
    
  • state

      1. shouldComponentUpdate
      2. v16.3 이전: componentWillUpdate =>  v16.3 이후: getSnapshotBeforeUpdate
      3. render
      4. componentDidUpdate
    

Unmounting

- componentWillUnmount