프론트엔드/React

리액트 기초이론 4 - 컴포넌트의 생명주기 (Life cycle)

syleemomo 2021. 10. 22. 11:15
728x90

 

생명주기 참조문서

 

React.Component – React

A JavaScript library for building user interfaces

ko.reactjs.org

생명주기 예시

 

State and Lifecycle – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

* 컴포넌트 생명주기의 개념

컴포넌트가 웹 화면에 처음 렌더링되고, 사용자 이벤트에 의하여 화면이 업데이트되고, 사용자가 현재 웹 화면에서 다른 페이지로 이동하면서 컴포넌트는 각자의 라이프 사이클을 가진다. 사람이 처음 태어나서 외모가 변하고 언젠가 생명을 마감하는 것에 비유된다. 

 

* 라이프사이클 도식화 그림

참조그림

 

React Lifecycle Methods diagram

Fully interactive and accessible React Lifecycle Methods diagram.

projects.wojtekmaj.pl

생명주기는 크게 3가지로 분류된다. 컴포넌트가 생성되어 DOM 에 삽입된 경우, 컴포넌트가 업데이트되어 DOM 을 변경해야 하는 경우, 마지막으로 컴포넌트가 DOM 에서 해제되는 경우이다. 각각의 경우에 컴포넌트에서 호출되는 메서드들이 존재한다. 이를 라이프사이클 메서드 또는 생명주기 메서드라고 한다. 

 

* 라이프사이클 메서드와 역할

마운트 - 컴포넌트가 생성되어 DOM 에 삽입되는 경우

메서드 호출 순서는 다음과 같다. 생성자(constructor)가 맨 처음 호출되어 부모 컴포넌트로부터 props 를 전달받고 state 를 초기화한다. 그 다음 render 함수가 호출되면 컴포넌트를 생성한다. JSX 문법 파트에서 설명했던 자바스크립트 객체 형태이다. 마지막으로 실제 DOM 트리에 컴포넌트를 삽입한다. 이를 완료하면 componentDidMount 메서드가 호출된다. 

업데이트 - 컴포넌트가 업데이트되고 DOM 을 변경하는 경우

메서드 호출 순서는 다음과 같다. 사용자 이벤트가 발생한다. 이벤트 핸들러 함수에서 setState 메서드가 호출된다. 그 다음 render 함수가 호출되고 변경된 state 로 컴포넌트를 재생성한다. 이후에 재생성한 컴포넌트로 DOM 을 업데이트한다. 이를 완료하면 componentDidUpdate 메서드가 호출된다. 

마운트 해제 - 컴포넌트가 DOM 에서 제거되는 경우

componentWillUnmount 메서드가 호출된다. 이 메서드에서는 컴포넌트가 해제되기 직전에 호출되므로 컴포넌트가 마운트될때 설정했던 것들을 해제하고 제거한다. componentDidMount 메서드에 타이머를 설정했다면 해당 메서드에서 해제한다. 

import './App.css';
import React, { Component } from 'react';

class App extends Component {
  constructor(props){
    console.log('constructor')
    super(props)
    this.state = {
      name: "syleemomo"
    }
  }
  changeName = () => {
    this.setState({name: "name changed"})
  }
  componentDidMount(){
    console.log('mount')
    console.log('----------')
  }
  componentDidUpdate(){
    console.log('update')
  }
  componentWillUnmount(){
    console.log('unmount')
  }
  
  render(){
    console.log('render')
    const {name} = this.state
    return (
      <div className="App">
        <h1>{name}</h1>
        <button onClick={this.changeName}>Change name</button>
      </div>
    )
  }
}

export default App;

App 컴포넌트에 위 코드를 작성하자! 개발자 도구를 열어서 콘솔창을 확인해보자!

컴포넌트 마운트

위와 같이 출력되는가? 컴포넌트가 마운트 될때 constructor 가 먼저 실행되고 render 함수가 호출되고 componentDidMount 메서드가 마지막으로 호출되는 것을 확인할 수 있다. 

컴포넌트 업데이트

버튼을 클릭해보자! 버튼을 클릭하면 컴포넌트가 업데이트된다. setState 메서드에 의하여 render 함수가 호출되고 componentDidUpdate 메서드가 호출됨을 확인할 수 있다. 

 

* render 

render 는 클래스형 컴포넌트에서 반드시 정의되어야 하는 유일한 메서드이다. 해당 메서드가 실행되면 this.props 와 this.state 를 이용하여 반드시 리액트 엘리먼트를 반환해야 한다. 아래는 자주 하는 실수중 하나다. 

import './App.css';
import React, { Component } from 'react'

class App extends Component{
  state = {
    friends: null
  }
  setFriends = () => {
    this.setState({ friends: [
      "sunrise",
      "vicvoria",
      "hanna"
    ] })
  }

  render(){
    const { friends } = this.state

    if(friends){
      return (
        <div>친구목록 : {friends.join(', ')}</div>
      ) 
    }
  }
}

export default App;

friends 상태(state)가 null 이 아니면 반환값이 존재한다. 그러나 초기에는 friends 상태(state)가 null 이므로 조건문을 만족하지 못하고 아무것도 반환되는 값이 없다. 즉, 리액트 엘리먼트를 반환하지 않으므로 아래와 같은 에러 메세지를 출력하고 화면에 아무것도 보이지 않는다.

리액트 엘리먼트를 반환하지 않은 경우의 에러 메세지

 

아래와 같이 조건문을 만족하지 못하는 경우에는 불리언(Boolean) 값이나 null 값 또는 JSX 엘리먼트를 설정해주는 것이 좋다. 

import './App.css';
import React, { Component } from 'react'

class App extends Component{
  state = {
    friends: null
  }
  setFriends = () => {
    this.setState({ friends: [
      "sunrise",
      "vicvoria",
      "hanna"
    ] })
  }

  render(){
    const { friends } = this.state

    if(friends){
      return (
        <div>친구목록 : {friends.join(', ')}</div>
      ) 
    }else{
      return (
        <>
          <div>친구목록이 존재하지 않습니다.</div>
          <button onClick={this.setFriends}>친구목록 갱신</button>
        </>
      )
    }
  }
}

export default App;

false 나 null 을 반환하는 경우 화면에 아무것도 보이지 않는다. 

 

* constructor

constructor 는 컴포넌트가 마운트 되기 전에 초기에 한번만 실행된다. 그러므로 아래와 같이 컴포넌트에서 사용할 상태(state)를 초기화해주고, 이벤트핸들러 함수에 this 값을 바인딩해줘야 하는 경우에 정의한다. 

import './App.css';
import React, { Component } from 'react'

class App extends Component{
  constructor(props){
    super(props)
    this.state = {
      color: "red"
    }
    this.changeColor = this.changeColor.bind(this)

  }
  changeColor(){
    this.setState({ color: "blue" })
  }

  render(){
    const { color } = this.state

    return (
      <>
        <div>{color}</div>
        <button onClick={this.changeColor}>색상 변경</button>
      </>
    ) 
  }
}

export default App;

위 코드는 버튼이 클릭되면 색상에 대한 문자열을 변경한다.  

constructor(props){
    super(props)
    this.state = {
      color: "red"
    }
    this.changeColor = this.changeColor.bind(this)
}

changeColor 를 화살표 함수로 정의하지 않으면 this 값은 undefined 가 된다. 그러므로 constructor 생성자에서 this 값을 바인딩해주어야 한다. 바인딩해주는 this 값은 App 컴포넌트를 가리킨다. 

 

* componentDidMount 

componentDidMount 메서드는 컴포넌트가 DOM 트리에 마운트된(삽입된) 직후에 리액트에 의해 자동으로 호출된다. DOM 노드가 있어야 가능한 작업은 여기서 하면 된다. 즉, DOM 을 직접 변경해야 한다면 여기서 하면 된다. 

import './App.css';
import React, { Component } from 'react'

class App extends Component{
  componentDidMount(){
    const photoBox = document.querySelector('.photo-box')
    photoBox.innerHTML = "포토 박스"
  }

  render(){
    return (
      <>
        <div className='photo-box'>
          컨텐츠 없음
        </div>
      </>
    ) 
  }
}

export default App;

위 코드는 render 메서드에서 클래스명이 'photo-box' 인 요소를 화면에 렌더링한다. 이후 componentDidMount 메서드에서는 컴포넌트가 DOM 에 삽입된 직후이므로 해당 요소에 접근과 변경이 가능하다. 

 

import './App.css';
import React, { Component } from 'react'

const colors = ["red", "blue", "green", "orange", "skyblue"]

class App extends Component{
  state = {
    colorIndex: 0
  }
  changeColor = () => {
    this.setState({colorIndex: this.state.colorIndex + 1})
  }
  componentDidMount(){
    this.timerId = setInterval(this.changeColor, 1000)
  }
  componentWillUnmount(){
    clearInterval(this.timerId)
  }

  render(){
    const { colorIndex } = this.state
    const color = colors[colorIndex % colors.length]

    return (
      <div className={`color-box ${color}`}>
        {color}
      </div>
    ) 
  }
}

export default App;

App.js 파일을 위와 같이 작성하자!

.color-box{
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 100px;
  font-weight: bold;
  color: white;
}
.red{
  background: red;
}
.blue{
  background: blue;
}
.green{
  background: green;
}
.orange{
  background: orange;
}
.skyblue{
  background: skyblue;
}

App.css 파일을 위와 같이 작성하자!

 

위 코드는 1초마다 배경화면의 색상을 변경하는 예제이다. 

const colors = ["red", "blue", "green", "orange", "skyblue"]

색상을 선택하기 위한 색상 배열을 정의한다. 

state = {
    colorIndex: 0
}

특정 색상을 선택하기 위하여 색상 배열에서 현재의 인덱스 값을 가지는 colorIndex 상태(state)를 초기화한다. 

const { colorIndex } = this.state
const color = colors[colorIndex % colors.length]

colorIndex 상태를 이용하여 색상 배열에서 하나의 색상을 선택한다. 

<div className={`color-box ${color}`}>
    {color}
</div>

스타일 코드에서 선택한 색상으로 배경화면 색상을 변경한다. 

componentDidMount(){
    this.timerId = setInterval(this.changeColor, 1000)
}

1초마다 색상이 변경되도록 setInterval 메서드를 사용하여 타이머를 시작한다. 타이머가 시작되면 changeColor 메서드가 1초마다 실행된다. 이러한 작업을 구독(subscription) 이라고 한다. 

changeColor = () => {
    this.setState({colorIndex: this.state.colorIndex + 1})
}

색상배열에서 다음 색상을 선택하기 위하여 colorIndex 값을 1만큼 증가시킨다. 

componentWillUnmount(){
    clearInterval(this.timerId)
}

 컴포넌트가 DOM 에서 제거되기 전에 반드시 구독을 해제해줘야 한다. 위 코드에서 구독 해제는 타이머 해제를 의미한다. 즉, App 컴포넌트가 DOM 트리에서 언마운트(unmount) 되기 전에 componentDidMount 메서드에서 설정한 타이머를 componentWillUnmount 메서드에서 해제해줘야 한다. 

배경화면 색상변경 결과

 

* componentDidUpdate

componentDidUpdate 는 초기 렌더링시에는 호출되지 않고, 이벤트핸들러 함수에 의하여 상태(state)가 업데이트 될때마다 갱신 직후에 호출된다. 

import './App.css';
import React, { Component } from 'react'

class App extends Component{
  state = {
    cnt: 0
  }
  increase = () => {
    this.setState({ cnt: this.state.cnt + 1})
  }
  componentDidUpdate(prevProps, prevState){
    console.log('카운트 업데이트 !')
    console.log('직전 카운트 값: ', prevState)
  }

  render(){
    const { cnt } = this.state

    return (
      <div className='center'>
        <div>{cnt}</div>
        <button onClick={this.increase}>카운트 증가</button>
      </div>
    )
  }
}

export default App;

위 코드는 버튼을 클릭할때마다 숫자를 카운팅하는 예제이다. 버튼을 클릭하면 이벤트핸들러인 increase 메서드가 먼저 호출된다. 다음은 setState 메서드에 의하여 cnt 상태(state)가 업데이트된다. 이후 render 메서드가 재실행되어 리렌더링이 일어난다. 마지막으로 상태가 업데이트되었으므로 componentDidUpdate 메서드가 실행되면서 아래와 같이 이전 상태를 화면에 출력한다.

버튼을 클릭할때마다 실행되는 componentDidUpdate 메서드

 

import './App.css';
import React, { Component } from 'react'

class App extends Component{
  state = {
    cnt: 0
  }
  increase = () => {
    this.setState({ cnt: this.state.cnt + 1})
  }
  componentDidUpdate(prevProps, prevState){
    console.log('카운트 업데이트 !')
    console.log('직전 카운트 값: ', prevState)

    this.increase() // 재귀적으로 계속 실행됨
  }

  render(){
    const { cnt } = this.state

    return (
      <div className='center'>
        <div>{cnt}</div>
        <button onClick={this.increase}>카운트 증가</button>
      </div>
    )
  }
}

export default App;

위 코드는 componentDidUpdate 메서드 안에서 다시 increase 메서드를 호출한다. 이렇게 하면 처음 버튼을 클릭했을때 아래와 같은 순서로 메서드가 호출된다. increase -> render -> componentDidUpdate -> increase -> render -> componentDidUpdate -> increase ... 이러한 순서로 재귀적으로 무한반복 실행된다.

componentDidUpdate 메서드에서 setState 메서드를 호출한 경우의 에러 메세지 출력

하지만 리액트는 위와 같이 무한루프를 방지하기 위하여 최대로 반복 가능한 횟수를 정해놓고 임계점을 넘어가면 프로그램 실행을 정지하고 에러 메세지를 출력하도록 설계되어 있다. 

 

import './App.css';
import React, { Component } from 'react'

const fruits = ["apple", "banana", "orange"]

class App extends Component{
  state = {
    fruit: fruits[0]
  }
  changeFruitOrNot = () => {
    this.setState({ fruit: fruits[Math.floor(Math.random()*fruits.length)]})
  }
  componentDidUpdate(prevProps, prevState){
    if(this.state.fruit !== prevState.fruit){
      console.log('과일 변경됨 !')
      console.log('직전에 선택된 과일: ', prevState.fruit)
    }else{
      alert("현재 선택된 과일은 이전과 동일함")
    }
  }

  render(){
    const { fruit } = this.state

    return (
      <div className='center'>
        <div>{fruit}</div>
        <button onClick={this.changeFruitOrNot}>과일 변경하기</button>
      </div>
    )
  }
}

export default App;

위 코드는 버튼을 클릭할때마다 과일을 랜덤으로 선택하는 예제이다. 

changeFruitOrNot = () => {
    this.setState({ fruit: fruits[Math.floor(Math.random()*fruits.length)]})
}

이벤트핸들러 메서드에서는 내장객체인 Math 모듈을 이용하여 fruits 배열에서 랜덤으로 과일을 선택한다. 

componentDidUpdate(prevProps, prevState){
    if(this.state.fruit !== prevState.fruit){
      console.log('과일 변경됨 !')
      console.log('직전에 선택된 과일: ', prevState.fruit)
    }else{
      alert("현재 선택된 과일은 이전과 동일함")
    }
 }

fruit 상태(state)가 업데이트되면 componentDidUpdate 메서드가 호출되면서 위 코드블럭이 실행된다. componentDidUpdate 메서드에서는 위와 같이 prevProps, prevState 와 같은 파라미터를 사용할 수 있다. prevProps 는 업데이트 직전의 속성(props)이고, prevState 는 업데이트 직전의 상태(state)이다. 만약 fruit 상태가 직전과 동일하면 경고창을 띄워 알려주고, 변경되었으면 직전의 fruit 상태(state)를 출력한다. 

랜덤으로 과일을 선택하는 예제의 결과 화면

 

그럼 랜덤으로 과일을 선택하더라도 중복이 발생하지 않고 계속 다른 과일을 뽑을수는 없을까?

import './App.css';
import React, { Component } from 'react'

const fruits = ["apple", "banana", "orange"]

class App extends Component{
  state = {
    fruit: fruits[0]
  }
  changeFruitOrNot = () => {
    this.setState({ fruit: fruits[Math.floor(Math.random()*fruits.length)]})
  }
  componentDidUpdate(prevProps, prevState){
    if(this.state.fruit !== prevState.fruit){
      console.log('과일 변경됨 !')
      console.log('직전에 선택된 과일: ', prevState.fruit)
    }else{
      alert("현재 선택된 과일은 이전과 동일함")

      // 선택된 과일이 이전과 동일하면 한번더 과일을 선택하기
      this.changeFruitOrNot()
    }
  }

  render(){
    const { fruit } = this.state

    return (
      <div className='center'>
        <div>{fruit}</div>
        <button onClick={this.changeFruitOrNot}>과일 변경하기</button>
      </div>
    )
  }
}

export default App;

App 컴포넌트를 위와 같이 수정하자!

// 선택된 과일이 이전과 동일하면 한번더 과일을 선택하기
this.changeFruitOrNot()

fruit 상태를 체크해서 직전과 동일한 값이면 다시 changeFruitOrNot 메서드를 호출하여 fruit 상태를 변경할 수 있다. 만약 랜덤함수가 계속 동일한 과일을 선택한다면 changeFruitOrNot 메서드는 재귀적으로 호출되어 fruit 상태가 변경될때까지 과일 선택 과정을 반복한다. 

 

* componentWillUnmount

componentWillUnmount 는 컴포넌트가 마운트 해제되어 DOM 트리에서 제거되기 직전에 호출된다. 해당 메서드에서 구독 해제를 하면 된다. 예를 들어 componentDidMount 에서 네트워크 요청을 시도한 경우 해당 메서드에서 네트워크 요청을 취소하면 된다. 또는 componentDidMount 에서 설정한 타이머를 해제할 수도 있다. 

해당 메서드 안에서 setState 메서드를 호출하면 안된다. 컴포넌트가 마운트 해제되고 나면 setState 메서드를 호출하더라도 render 메서드가 호출되지 않는다. 

import React, { Component } from 'react';
import Counter from './Counter'

class App extends Component {
  state = {
    toggle: true 
  }
  changeToggle = () => {
    this.setState({ toggle: !this.state.toggle })
  }
  render() {
    const { toggle } = this.state 
    return (
      <div>
        {toggle? <Counter/> : <h1>컨텐츠 없음</h1>}
        <br/>
        <button onClick={this.changeToggle}>컴포넌트 보이기/사라지게 하기</button>
      </div>
    );
  }
}

export default App;

App.js 파일을 위와 같이 작성하자!

import Counter from './Counter'

카운팅을 수행하는 Counter 컴포넌트를 불러온다.

state = {
    toggle: true 
}

Counter 컴포넌트를 보여주거나 사라지게 하기 위한 toggle 상태를 정의한다. 

render() {
    const { toggle } = this.state 
    return (
      <div>
        {toggle? <Counter/> : <h1>컨텐츠 없음</h1>}
        <br/>
        <button onClick={this.changeToggle}>컴포넌트 보이기/사라지게 하기</button>
      </div>
    );
  }

toggle 상태를 조회한 다음 true, false 에 따라 Counter 컴포넌트를 보여주거나 "컨텐츠 없음" 이라는 문자열을 보여준다. toggle 상태를 변경하기 위한 버튼을 렌더링한다. 

changeToggle = () => {
    this.setState({ toggle: !this.state.toggle })
}

버튼을 클릭할때마다 toggle 상태를 true 에서 false 로 또는 false 에서 true 로 변경한다. 

import React, { Component } from 'react';

class Counter extends Component {
    state = {
        count: 0
    }
    componentDidMount(){
        this.timerId = setInterval(() => {
            this.setState({count: this.state.count + 1})
        }, 1000);
    }
    componentWillUnmount(){
        alert("해당 컴포넌트를 보이지 않게 하시겠어요?")
        clearInterval(this.timerId)
    }
    render() {
        const { count } = this.state 
        return (
            <div>
                <h1>카운팅: {count}</h1>
            </div>
        );
    }
}

export default Counter;

Counter 컴포넌트를 생성하자!

state = {
    count: 0
}

숫자 카운팅을 위한 count 상태를 정의한다. 

render() {
    const { count } = this.state 
    return (
        <div>
            <h1>카운팅: {count}</h1>
        </div>
    );
}

count 상태를 조회하고 화면에 보여준다. 

componentDidMount(){
    this.timerId = setInterval(() => {
        this.setState({count: this.state.count + 1})
    }, 1000);
}

componentDidMount 라이프 사이클 메서드를 이용하여 타이머를 설정하고 1초마다 count 상태를 1씩 증가시켜 카운팅한다. 

componentWillUnmount(){
    alert("해당 컴포넌트를 보이지 않게 하시겠어요?")
    clearInterval(this.timerId)
}

App 컴포넌트의 toggle 상태가 false 가 되면 Counter 컴포넌트는 DOM 트리에서 제거되므로 제거되기 직전에 위와 같이 componentWillUnmount 라이프 사이클 메서드가 실행된다. 사용자에게 컴포넌트를 제거해도 될지 물어본 다음에 확인 버튼을 클릭하면 타이머를 해제한다. 

 

* 라이프사이클 활용 예제

무비 리스트를 화면에 보여주는 컴포넌트를 만들어보자! 

import './App.css';
import React, { Component } from 'react';
import Movie from './Movie';

class App extends Component {
  constructor(props){
    super(props)
    this.state = {
      loading: true,
      movies: []
    }
  }
 
  componentDidMount(){
    fetch('https://yts.mx/api/v2/list_movies.json?limit=12')
    .then( res => res.json())
    .then( result => {
      const {data: {movies}} = result
      console.log(movies)
      this.setState({loading: false, movies})
    })
  }
  
  render(){
    const {loading, movies} = this.state
    const style = {
      display: 'flex',
      flexWrap: 'wrap',
      justifyContent: 'center',
      alignItems: 'center',
      width: '60%',
      margin: '100px auto',
      textAlign: 'center'
    }
    const loadingStyle = {
      position: 'absolute', 
      left: '50%', 
      top:'50%', 
      transform: 'translate(-50%, -50%)', 
      fontSize: '2rem'
    }
    if(loading){
      return (
        <div style={loadingStyle}>
          <h1>Loading ...</h1>
        </div>
      )
    }else{
      return (
        <div style={style}>
          {movies.map(movie => {
            return (
              <Movie 
                key={movie.id}
                title={movie.title}
                genres={movie.genres}
                cover={movie.medium_cover_image}
                summary={movie.summary}
              ></Movie>

            )
          })}
        </div>
      )
    }
  }
}

export default App;

App.js 파일에 위와 같이 작성하자!

this.state = {
  loading: true,
  movies: []
}

화면의 로딩 상태를 알려주는 state, 오픈 API 에서 가져온 무비 리스트를 담을 state 를 초기화하였다.

if(loading){
  return (
    <div style={loadingStyle}>
      <h1>Loading ...</h1>
    </div>
  )
}else{
  return (
    <div style={style}>
      {movies.map(movie => {
        return (
          <Movie 
            key={movie.id}
            title={movie.title}
            genres={movie.genres}
            cover={movie.medium_cover_image}
            summary={movie.summary}
          ></Movie>

        )
      })}
    </div>
  )
}

render 함수 안에서는 loading 상태에 따라 로딩 화면을 보여주거나 무비 리스트를 보여주도록 하였다. JSX 문법에서는 중괄호 안에 자바스크립트 표현식이 들어갈 수 있으므로 배열 메서드인 map 을 이용하여 무비 데이터를 Movie 컴포넌트로 변환한다. Movie 컴포넌트의 props 로 title, genres, cover, summary 를 전달한다. 

브라우저에서 직접 https://yts.mx/api/v2/list_movies.json 주소로 접속하면 JSON 데이터를 확인할 수 있다. 무비 데이터의 구조는 아래와 같다. 많은 필드가 있지만 여기서는 title, genres, medium_cover_image, summary 만 간단히 사용하였다. 

무비 데이터 스키마 1
무비 데이터 스키마 2

오픈 API 참고문서

 

API Documentation - YTS YIFY

Official YTS YIFY API documentation. YTS offers free API - an easy way to access the YIFY movies details.

yts.mx

componentDidMount(){
  fetch('https://yts.mx/api/v2/list_movies.json?limit=12')
  .then( res => res.json())
  .then( result => {
    const {data: {movies}} = result
    console.log(movies)
    this.setState({loading: false, movies})
  })
}

App 컴포넌트가 DOM 에 마운트되면 componentDidMount 메서드가 호출된다. 즉, 웹페이지 화면이 다 그려지면 호출된다. 여기서는 오픈 API 서버에 접속하여 무비 리스트 데이터를 가져온다. setState 메서드로 state 를 업데이트하면 render 함수가 다시 호출되면서 로딩 화면이 아니라 무비 리스트가 브라우저 화면에 보인다. fetch 함수는 비동기로 동작하며 API 주소에 접속하고 데이터를 가져온다. 

import React from 'react';

function Movie({title, genres, cover, summary}){
    const style = {
        width: '230px',
        height: '500px',
        background: "white",
        margin: '10px',
        boxShadow: 'rgba(0, 0, 0, 0.35) 0px 5px 15px'
    }

    return (
        <div style={style}>
            <img src={cover} alt={title}></img>
            <h3>{title}</h3>
            <h4>{genres.join(" ")}</h4>
            {/* <p>{summary}</p> */}
        </div>
    )
}
 
export default Movie;

Movie.js 파일에 위와 같이 작성하자!

Movie 컴포넌트 내부에서는 전달받은 title, genres, cover, summary 데이터를 이용하여 화면에 렌더링한다. genres 는 배열이므로 join 메서드를 이용하여 하나의 문자열로 변환하였다. 

 

무비 리스트 결과화면

 

1초마다 자동으로 숫자를 카운팅하는 컴포넌트를 만들어보자!

import './App.css';
import { Component } from 'react';

class App extends Component {
  state = {
    count: 0
  }
  increaseCount = () => {
    this.setState({ count: this.state.count + 1})
  }
  componentDidMount(){
    this.countID = setInterval(
      this.increaseCount
    , 1000)
  }
  componentWillUnmount(){
    clearInterval(this.countID)
  }
  render(){
    const { count } = this.state
    return (
      <div className="App">
        <h1>Increase count automatically !</h1>
        <h2>{ count }</h2>
      </div>
    );
  }
}

export default App;

App.js 파일을 위와 같이 수정하자! 

state = {
  count: 0
}

count state 를 0으로 초기화한다. 

increaseCount = () => {
  this.setState({ count: this.state.count + 1})
}

 

count 를 1씩 증가시킨다. 

componentDidMount(){
  this.countID = setInterval(
    this.increaseCount
  , 1000)
}

setInterval 함수는 윈도우 객체의 메서드이며 브라우저 API 이다. 두번째 인자로 주어진 시간간격만큼 콜백함수를 실행시킨다. 여기서는 1초(1000ms)마다 한번씩 increaseCount 메서드를 호출하고 실행한다. this.countID 는 setInterval 함수가 반환하는 타이머 ID 값이다. 

componentWillUnmount(){
  clearInterval(this.countID)
}

현재 웹페이지를 벗어나면 componentWillUnmount 메서드가 호출되므로 이때 타이머를 해제(중지)한다. 

render(){
  const { count } = this.state
  return (
    <div className="App">
      <h1>Increase count automatically !</h1>
      <h2>{ count }</h2>
    </div>
  );
}

count 값을 조회해서 웹화면에 렌더링한다. 

 

그럼 이 코드를 응용해서 사진 데이터를 순차적으로 조회하면서 웹화면에 보여주는 컴포넌트를 만들어보자! 말하자면 이미지 갤러리이다. 

구글 이미지 검색

구글 이미지 검색에서 내가 보여주고 싶은 이미지에서 마우스 우클릭을 하고, 이미지 주소 복사를 선택한다. 이미지 주소 복사를 하면 이미지 데이터가 복사된다. 이미지 데이터는 base64string 형태이다. 

const dummyData = [
    {
        title: '고양이',
        src: 'data:image/jpeg;base64,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'
    },
    {
        title: '강아지',
        src: 'data:image/jpeg;base64,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'
    },
    {
        title: '햄스터',
        src: 'data:image/jpeg;base64,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'
    },
    {
        title: '돼지',
        src: 'data:image/jpeg;base64,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'
    },
    {
        title: '고슴도치',
        src: 'data:image/jpeg;base64,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'
    },
]
export default dummyData;

dummyData.js 를 위와 같이 수정하자! 

import './App.css';
import { Component } from 'react';
import animals from './dummyData'

class App extends Component {
  state = {
    count: 0
  }
  increaseCount = () => {
    this.setState({ count: this.state.count + 1})
  }
  componentDidMount(){
    this.countID = setInterval(
      this.increaseCount
    , 1000)
  }
  
  componentWillUnmount(){
    clearInterval(this.countID)
  }
  render(){
    const { count } = this.state
    const animal = animals[count%animals.length]
    console.log(animal)
    return (
      <div className="App">
        <h1>Image Gallery !</h1>
        <img src={animal.src} alt={animal.title}></img>
      </div>
    );
  }
}

export default App;

App.js 를 위와 같이 수정하자! 

import animals from './dummyData'

dummyData.js 파일을 임포트해서 동물에 관련된 데이터를 가져온다.  

render(){
    const { count } = this.state
    const animal = animals[count%animals.length]
    console.log(animal)
    return (
      <div className="App">
        <h1>Image Gallery !</h1>
        <img src={animal.src} alt={animal.title}></img>
      </div>
    );
  }

count 는 계속 증가하지만 animals 배열의 데이터는 한정되어 있으므로 animals[count] 로 코드를 작성하면 결국에는 배열의 인덱스를 조회할 수 없다는 에러 메세지를 반환한다. 그러므로 count%animals.length 로 배열의 인덱스 값만 조회할 수 있도록 한다. 현재 animals 배열의 길이는 5이므로 count%animals.length 를 하게 되면 0, 1, 2, 3, 4 를 계속 생성하면서 배열 요소를 순회한다. 

이미지 갤러리 화면

 

 

* 연습과제 1

JSX 문법 수업주제의 연습과제에서 만든 Dictionary 컴포넌트에서 웹 화면이 처음 렌더링되었을때 (라이프사이클 메서드 사용하기) 우리가 만든 사전 검색 서비스의 서버에서 데이터를 가져와서 Dictionary 컴포넌트에서 렌더링해보자!

 

* 연습과제 2

오늘 수업의 자동 카운팅 예제와 이미지 갤러리 예제를 활용하여 아래와 같이 로또번호 6개를 자동 생성하고, 1초마다 보여주는 컴포넌트를 만들어보자! 로또 번호는 1~45 사이 숫자 중 하나를 랜덤으로 뽑는다. (단, 6개의 숫자는 모두 달라야 한다. 즉, 중복이 없어야 한다.)

1초마다 로또번호 6개를 보여주는 로또번호 자동 생성기

 

pickRandomNumber = (min, max) => {
  return Math.floor( Math.random() * (max-min+1) ) + min
}

특정한 범위(min <= number <= max)에서 숫자를 랜덤으로 선택하는 코드는 위와 같다. 즉, 로또번호를 뽑으려면 pickRandomNumber(1, 45) 와 같이 호출하면 된다. 

 

* 연습과제 3

const dummyData = [
    {
        word: 'apple',
        meaning: '사과'
    },
    {
        word: 'before',
        meaning: '이전의'
    },
    {
        word: 'clean',
        meaning: '깨끗한'
    },
    {
        word: 'dummy',
        meaning: '가짜의'
    },
    {
        word: 'emergent',
        meaning: '긴급한'
    },
    {
        word: 'famouse',
        meaning: '유명한'
    },
    {
        word: 'give',
        meaning: '(~을) 주다'
    },
    {
        word: 'humble',
        meaning: '검소한'
    },
    {
        word: 'ingrave',
        meaning: '조각하다'
    },
    {
        word: 'jungle',
        meaning: '밀림숲'
    },
    {
        word: 'korea',
        meaning: '대한민국'
    },
  
]
export default dummyData;

dummyData.js 파일을 위와 같이 수정하자! 주어진 데이터를 임포트하고 랜덤으로 보여주는 플래쉬카드 영어 단어장 컴포넌트를 만들어보자! 1초에 한 단어씩 랜덤으로 뽑아서 보여주면 된다. 

 

* 연습과제 4

OPEN API 서버로부터 화장품 데이터를 가져와서 화면에 보여주자! Price 버튼을 클릭하면 가격이 낮은 상품부터 정렬해서 보여주고, 다시 버튼을 클릭하면 초기 화면에서의 상품순으로 보여주도록 하자! OPEN API 서버 주소는 다음과 같다. (힌트 :

 

 

const API_URL = 'http://makeup-api.herokuapp.com/api/v1/products.json?brand=maybelline'

초기 화면에서의 상품순&amp;amp;nbsp;
가격이 낮은 상품부터 정렬된 화면

 

스타일을 적용하기 위한 CSS 파일은 아래와 같다. 아래 코드를 클래스명으로 설정하면 화면에 위와 같이 보여진다.  

.header{
  width: 100%;
  height: 70px;
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  box-shadow: 1px 1px 5px 5px darkgray;
  background: white;
  z-index: 1;

  display: flex;
  justify-content: flex-end;
  align-items: center;
}
.sort-btns{
  all: unset;
  width: 100px;
  height: 50px;
  background: peru;
  border-radius: 10px;
  cursor: pointer;
  color: white;
  font-size: 1rem;
  font-weight: bold;
  text-align: center;
  margin-right: 10px;
}
.sort-btns:hover{
  opacity: 0.8;
}
.root{
  width: 60%;
  margin: 100px auto;
  
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
}
.product{
  flex: 200px;
  height: 500px;
  box-shadow: 1px 1px 5px 5px peru;
  color: white;
  background: peru;
  margin: 10px;
  overflow: hidden;
}
.product-img{
  width: 100%;
  height: 180px;
  overflow: hidden;
}
.product-img img{
  width: 100%;
  height: 100%;
}
.product-name{
  font-weight: bold;
  font-size: 1.1rem;
  text-align: center;
}
.product-description{
  font-weight: 400;
  font-size: 0.9rem;
  text-align: center;
  margin-top: 15px;
}

 

* 연습과제 5

Node.js 수업에서 만든 할일목록(Todo) 앱 서버를 실행하고, 라이프사이클 메서드를 사용하여 아래와 같이 할일목록을 브라우저 화면에 렌더링해보자! (단, 명령창을 관리자 권한으로 실행해서 net start MongoDB 로 몽고 DB 서버가 켜져 있는지 확인하고, Node.js 서버의 CORS 옵션에 리액트 서버 주소인 localhost:3000 주소가 포함되어 있는지 확인한다.)

할일목록 출력 결과 화면

 

 

728x90