본문 바로가기
리액트

[react] 예제로 따라하는 리액트 훅(hook) - useEffect

by jaewooojung 2019. 8. 3.

ReactJS


*이전글

2019.08.02 - [react] 예제로 따라하는 리액트 훅(hook) - useState

 

[react] 예제로 따라하는 리액트 훅(hook) - useState

간단한 예제를 통해서 리액트 훅의 useState을 살펴보겠습니다. 작업의 처음단계부터 하나씩 진행하니 리액트에 처음 입문하시는 분들도 천천히 진행해보시길 바랍니다. create-react-app으로 프로젝

codingbroker.tistory.com


useEffect

useState에 이어서 이번 글에서는 useEffect를 살펴보겠습니다.

 

useEffect는 컴포넌트의 side effect를 수행하기 위해 사용됩니다.

side effect란 컴포넌트가 화면에 그려지는 초기 렌더링과정에 포함되지 않는 별개의 작업으로

대표적으로 HTTP통신이 있습니다.

 

이 글에서는

1. HTTP통신으로 게시글 정보를 받아와서

2. state에 저장한 후

3. 화면에 출력하는 예시를 작성해 보겠습니다.

 

사용할 URL은 https://jsonplaceholder.typicode.com/posts 입니다.

위 URL로 HTTP GET요청을 보내면 게시글 목록을 요소로 하는 배열을 받아올 수 있습니다.

링크를 클릭하시면 화면에 출력할 데이터들을 확인해 볼 수 있습니다.

 

(이 글은 기본적인 useState의 사용법에 대해서는 설명하지 않습니다.)

 

create-react-app으로 프로젝트를 설치합니다.

npx create-react-app hooks-react

 

프로젝트를 실행합니다.

code hooks-react

 

기본화면을 지우기 위해 src폴더에서 App.js와 index.js를 제외한 모든 파일을 삭제합니다.

프로젝트 폴더

 

스타일 작업을 위해 styled-components를 설치하겠습니다.

 

styled-components에 관한 자세한 설명은 아래 글을 참고해 주세요.

2019.07.30 - [react] 스타일드 컴포넌트(styled components)

 

[react] 스타일드 컴포넌트(styled components)

1. Styled-components? styled-components는 react와 react-native에서 스타일을 적용하는 데 사용되는 라이브러리입니다. styled-components 없이 전통적인 CSS 방식(css 혹은 scss 임포트)으로 애플리케이션에 스타일을

codingbroker.tistory.com

 

styled-components 설치

npm install styled-components

 

설치 후

App.js에서 styled-components와 useState을 불러옵니다.

 

index.js와 App.js의 초기상태는 다음과 같습니다.

 

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));

 

App.js

import React, { useState } from "react";
import styled from "styled-components";

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

const Container = styled.div``;

export default App;

 

styled-components로 최상위 div인 Container를 생성하였습니다.

 

이제 본격적으로 시작할 준비가 되었습니다.

 

1. state 선언

HTTP통신을 통해 가져온 배열을 저장할 state을 선언합니다.

 

App.js

import React, { useState } from "react";
import styled from "styled-components";

function App() {
  const [posts, setPosts] = useState([]);
  return <Container>App</Container>;
}

const Container = styled.div``;

export default App;

 

useState을 통해 posts라는 이름의 state과 이를 변경하는 setPosts함수를 생성했습니다.

posts에는 배열이 저장되므로 초기값으로 빈 배열( [ ] )을 주었습니다.

 

 

2. 화면 만들기

HTTP통신을 하기 전에 화면에 출력할 기본 틀을 먼저 만들어줍니다.

Title에는 글 제목이, Body에는 글 내용이 들어가게 됩니다.

 

App.js

import React, { useState } from "react";
import styled, { createGlobalStyle } from "styled-components";

function App() {
  const [posts, setPosts] = useState([]);
  return (
    <Container>
      <GlobalStyle />
      <Post>
        <Title>Title1</Title>
        <Body>Body1</Body>
      </Post>
      <Post>
        <Title>Title2</Title>
        <Body>Body2</Body>
      </Post>
      <Post>
        <Title>Title3</Title>
        <Body>Body3</Body>
      </Post>
      <Post>
        <Title>Title4</Title>
        <Body>Body4</Body>
      </Post>
    </Container>
  );
}

const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
  }
`;

const Container = styled.div`
  min-height: 100vh;
  padding: 200px 0;
  display: grid;
  grid-template-columns: repeat(4, 300px);
  grid-template-rows: repeat(auto-fit, 300px);
  grid-auto-rows: 300px;
  grid-gap: 30px 20px;
  justify-content: center;
  background: #55efc4;
  box-sizing: border-box;
`;

const Post = styled.div`
  border: 1px solid black;
  border-radius: 20px;
  background: white;
  box-shadow: 10px 5px 5px #7f8fa6;
`;

const Title = styled.div`
  height: 20%;
  display: flex;
  justify-content: center;
  align-items: center;
  border-bottom: 1px solid black;
  font-weight: 600;
`;

const Body = styled.div`
  height: 80%;
  padding: 11px;
  border-radius: 20px;
`;

export default App;

기본 틀 완성

 

일단 틀을 잡기 위해 <Post> 4개를 하나씩 만들었습니다만, 이후에는 자바스크립트 Array method를 활용해서 더 짧고 쉽게 <Post>를 만들게 됩니다.

 

 

3. HTTP요청 및 useEffect

다음으로 HTTP요청을 위해 axios를 설치합니다. fetch를 사용하셔도 무방합니다.

npm install axios

 

App.js에서 useEffect와 axios를 불러와줍니다.

 

App.js

import React, { useState, useEffect } from "react";
import styled, { createGlobalStyle } from "styled-components";
import axios from "axios";

function App() {
  // ...

 

다음으로 useEffect를 사용하겠습니다. 인자로 함수를 전달합니다.

import React, { useState, useEffect } from "react";
import styled, { createGlobalStyle } from "styled-components";
import axios from "axios";

function App() {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    axios
      .get("https://jsonplaceholder.typicode.com/posts")
      .then(response => console.log(response));
  });
  return (
// ...

axios를 통해 HTTP요청을 보내는 코드입니다. 이렇게 하면 컴포넌트가 렌더링 될 때마다 useEffect가 실행됩니다.

 

then()에서는 HTTP요청을 통해 받아온 데이터를 처리할 수 있습니다. 우선 테스트를 위해 받아온 데이터를 console에 출력합니다.

 

결과는 아래와 같습니다.

console.log(response)

콘솔창에 보이듯이 axios를 사용하여 HTTP통신을 보내면 결괏값이 response 내부의 data에 저장됩니다. data라는 배열 속에 게시글들이 담겨있죠? 게시글의 수는 무려 100개입니다.

 

 

4. 데이터를 posts state에 저장

데이터를 확인했으니 console.log를 지우고 이제 posts state에 저장합니다.

 

App.js의 useEffect

useEffect(() => {
    axios
      .get("https://jsonplaceholder.typicode.com/posts")
      .then(({ data }) => setPosts(data));
  }, []);

({ data }) 는 es6의 Destructing 문법입니다. 이렇게 하면 response객체 안에 있는 data배열을 바로 참조할 수 있습니다.

setPosts에 data를 넣어주었으니 이제 posts state에 게시글들이 저장됩니다.

 

이때, useEffect 내부에서 state을 변경시킨 결과로 인해 컴포넌트의 리렌더링이 일어나게 되는데요. 렌더링시에는 다시 useEffect가 실행되니 현재 코드를 실행해 보면 아래와 같이 무한루프에 빠지게 됩니다.

렌더링 -> useEffect -> posts state 변화 -> 렌더링 -> useEffect -> posts state 변화 -> 렌더링

 

이를 해결하기 위해 useEffect에 두 번째 인자를 전달합니다.

두 번째 인자로 배열을 전달하면 렌더링시에 배열 내의 요소가 변화될 때에만 useEffect를 실행합니다. 빈 배열( [] )을 전달하면 변화를 감지할만한 요소 자체가 없으므로 useEffect는 최초 렌더링시에 한 번만 실행되는 것이 보장됩니다.

 

 

5. posts 출력

마지막 단계입니다.

posts에 저장된 값을 화면에 출력해 줍니다.

 

App.js

// ...
function App() {
  const [posts, setPosts] = useState([]);
  useEffect(() => {
    axios
      .get("https://jsonplaceholder.typicode.com/posts")
      .then(({ data }) => setPosts(data));
  }, []);
  return (
    <Container>
      <GlobalStyle />
      {posts.map((post, index) => (
        <Post key={index}>
          <Title>{post.title}</Title>
          <Body>{post.body}</Body>
        </Post>
      ))}
    </Container>
  );
}
// ...

return 내부에 있는 코드를 리액트 element인 JSX라고 부릅니다. JSX안에서는 중괄호( { } )를 사용해 자바스크립트를 사용할 수 있습니다.

 

posts안에 있는 100개의 요소를 모두 출력하기 위해 자바스크립트의 Array.map() 메소드를 사용하였습니다.

이때,  <Post>에는 key prop으로 각각을 식별할 수 있는 고유한 값을 설정해줘야 합니다. 여기서는 배열 내에서의 index를 key prop으로 설정하였습니다.

 

map()으로 해당 posts 요소를 처음부터 끝까지 순회하면서 해당 데이터를 가진 Post 컴포넌트를 반환해 줍니다.

 

처음에 <Post> 4개를 직접 코딩한 것 기억하시나요?

위처럼 map()을 사용하면 짧은 코드로 배열의 요소 전부를 출력할 수 있습니다.

 

실행화면을 보시죠

완성

완성되었습니다.

 

수고 많으셨습니다!



        
답변을 생성하고 있어요.