만들면서 배우는 리액트 튜토리얼 - 5.State

by - August 29, 2018


State 리액트 컴포넌트 안에 있는 객체이다.

중요한 것은 State 바뀔 때마다, 새로운 state 함께 다시 render() 실행된다는 것이다.

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

const movies = [
  {
    title:"Matrix",
    poster:"https://images-na.ssl-images-amazon.com/images/I/51vpnbwFHrL._SY445_.jpg",
  },
  {
    title:"Full Metal Jacket",
    poster:"https://i.pinimg.com/originals/36/1e/cd/361ecdb85a3767f70810cbe2cdaaf1a4.jpg",
  },
  {
    title:"Oldboy",
    poster:"https://m.media-amazon.com/images/M/MV5BYjQwZTc3ODktZjk1ZS00N2Y3LWFlYmUtMmQ4M2IwMjZlYTIwXkEyXkFqcGdeQXVyNjQwMzk1MDM@._V1_.jpg",
  },
  {
    title:"Star wars",
    poster:"http://cdn.shopify.com/s/files/1/0151/0741/products/Star_Wars_Portrait-NGPS1263_Copy_1024x1024.jpg?v=1504676565",
  },
]

class App extends Component {

  state = {
    greeting: 'Hello'
  }

  // 5 state greeting Hello again!으로 바꿔라!
  componentDidMount() {
    setTimeout(() => {
      this.setState({ // this.state.greeting 직접 바꾸면 안됨
        greeting: 'Hello again!'
      })
    }, 5000)
  }

  render() {
    return (
      <div className="App">
      {this.state.greeting}
        {/* movies.map 하면 movie movies 객체가 하나씩 들어가고 {}안에 것을 리턴한다 */}
        {movies.map((movie, index) =>
          <Movie title={movie.title} poster={movie.poster} key={index} />
        )}
      </div>
    );
  }
}

export default App;

state 기본 예시

1.1. State 활용

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

class App extends Component {
  state = {
    movies: [
      {
        title:"Matrix",
        poster:"https://images-na.ssl-images-amazon.com/images/I/51vpnbwFHrL._SY445_.jpg",
      },
      {
        title:"Full Metal Jacket",
        poster:"https://i.pinimg.com/originals/36/1e/cd/361ecdb85a3767f70810cbe2cdaaf1a4.jpg",
      },
      {
        title:"Oldboy",
        poster:"https://m.media-amazon.com/images/M/MV5BYjQwZTc3ODktZjk1ZS00N2Y3LWFlYmUtMmQ4M2IwMjZlYTIwXkEyXkFqcGdeQXVyNjQwMzk1MDM@._V1_.jpg",
      },
      {
        title:"Star wars",
        poster:"http://cdn.shopify.com/s/files/1/0151/0741/products/Star_Wars_Portrait-NGPS1263_Copy_1024x1024.jpg?v=1504676565",
      },
    ]
  }

  componentDidMount() {
    // 5 이후에 실행
    setTimeout(() =>
    this.setState({
      movies: [
        ...this.state.movies, // 이전 state 그대로 두고
        // 아래 내용을 추가해라
        {
          title:"transporting",
          poster:"https://upload.wikimedia.org/wikipedia/en/thumb/7/71/Trainspotting_ver2.jpg/250px-Trainspotting_ver2.jpg",
        }
      ]
    }), 5000)
  }

  render() {
    return (
      <div className="App">
        {/* movies.map 하면 movie movies 객체가 하나씩 들어가고 {}안에 것을 리턴한다 */}
        {this.state.movies.map((movie, index) =>
          <Movie title={movie.title} poster={movie.poster} key={index} />
        )}
      </div>
    );
  }
}

export default App;

state 활용 예시

위의 코드는 기존 const 배열로 선언했던 movies state 바꾸고 setTimeout 사용하여 5 

이후에 새로운 영화를 기존 목록에 추가하는 코드이다. 배열 데이터가 state 바뀌었기 

때문에 render()에서도 this.state.movies.map으로 사용하며, 고유한 key 필요하다는 

warning 제거하기 위해 key prop으로 map에서 자동으로 넘어오는 index 넣어준다.


componentDidMount() {
    // 5 이후에 실행
    setTimeout(() =>
    this.setState({
      movies: [
        ...this.state.movies, // 이전 state 그대로 두고
        // 아래 내용을 추가해라
        {
          title:"trainspotting",
          poster:"https://upload.wikimedia.org/wikipedia/en/thumb/7/71/Trainspotting_ver2.jpg/250px-Trainspotting_ver2.jpg",
        }
      ]
    }), 5000)
  }

componentDidMout 사용하여 컴포넌트가 완전히 마운트 후에 setTimeout(fn, 5000) 

사용하여 5 뒤에 함수가 실행되게 한다. …this.state.movies 기존 state 목록을 불러온다

, 처음에는 기존 영화 리스트가 출력되고 5 뒤에 기존 목록 밑에 

다른 영화(trainspotting) 추가 되는 것이다.

1.2. Loading States(state 이용한 API call 구현)

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

class App extends Component {
  state = {
   
  }

  componentDidMount() {
    // 5 이후에 실행
    setTimeout(() =>
    this.setState({
      movies: [
        {
          title:"transporting",
          poster:"https://upload.wikimedia.org/wikipedia/en/thumb/7/71/Trainspotting_ver2.jpg/250px-Trainspotting_ver2.jpg",
        },
        {
          title:"Matrix",
          poster:"https://images-na.ssl-images-amazon.com/images/I/51vpnbwFHrL._SY445_.jpg",
        },
        {
          title:"Full Metal Jacket",
          poster:"https://i.pinimg.com/originals/36/1e/cd/361ecdb85a3767f70810cbe2cdaaf1a4.jpg",
        },
        {
          title:"Oldboy",
          poster:"https://m.media-amazon.com/images/M/MV5BYjQwZTc3ODktZjk1ZS00N2Y3LWFlYmUtMmQ4M2IwMjZlYTIwXkEyXkFqcGdeQXVyNjQwMzk1MDM@._V1_.jpg",
        },
        {
          title:"Star wars",
          poster:"http://cdn.shopify.com/s/files/1/0151/0741/products/Star_Wars_Portrait-NGPS1263_Copy_1024x1024.jpg?v=1504676565",
        },
      ]
    }), 5000)
  }

  _renderMovies = () => {
    const movies = this.state.movies.map((movie, index) =>
      <Movie title={movie.title} poster={movie.poster} key={index} />
    )
    return movies
  }

  render() {
    return (
      <div className="App">
        {/*
          this.state.movies 데이터가 존재하면 기존 state mapping 실행하고,
          아니면 Loading... string 띄워준다
        */}
        {this.state.movies ? this._renderMovies() : "Loading..."}
      </div>
    );
  }
}

export default App;

Loading State 구현 예시

실제 동작하는 프로그램에서는 처음부터 데이터가 존재하기 보다는 주로 API 통해서 데이터를 불러온다

위의 코드는 로딩 시간동안 Loading이라고 띄워주는 패턴의 예시이다.

우선 state 배열로 두고, componentDidMount() setTimeout() 이용하여 컴포넌트가 

마운트 되고 5 state 데이터를 추가해준다. 이렇게 하고 바로 this.state.movies 

render해주면 처음에 state 비어있기 때문에 5 데이터가 추가되기 전에 this.state 

존재하지 않는다는 에러가 발생한다.

그래서 _renderMovies()라는 함수를 정의해서 기존 mapping 코드를 변수 형태로 만들고 

변수 값을 return해준다. 그리고 실제 render()에서는 3 연산자(조건 ? : 거짓) 

이용하여 데이터가 존재하면 _renderMovies() 실행하고 데이터가 아직 없을 경우 

Loading…이라는 string 출력 해준다.


1.3. Smart vs Dumb Component(class vs function)

굳이 state componentDidMount() 같은 복잡한 기능들이 아니라 prop 필요한 단순한 

컴포넌트가 있다. Movie App에서 보면 기존에 구현한 MoviePoster 클래스가 그렇다.

Img 태그 하나를 리턴 다른 기능이 없기 때문에 굳이 class 만들 필요가 없다

이럴 때는 function으로 바꾸어서 구현하면 복잡한 기능을 빼고 심플하게 사용할 있다.


/*
class MoviePoster extends Component {

  static propTypes = {
    poster: PropTypes.string.isRequired,
  }

  render() {
    return(
      <img src={this.props.poster} />
    )
  }
}
*/

function MoviePoster({poster}) {
  return(
    <img src={poster} alt="Movie Poster" />
  )
}


예제 코드에서 아래 function과 주석처리된 위의 class 같은 기능을 수행한다.

You May Also Like

0 comments