본문 바로가기
REACT

[React] 272샘의 React14 ( useEffect Hook + fetch )

by 미눅스[멘토] 2024. 10. 31.
728x90

 

 

 

https://deahan.tistory.com/433

 

[React] 272샘의 React13 ( useEffect Hook )

https://deahan.tistory.com/432 [React] 272샘의 React12 ( useRef Hook )https://deahan.tistory.com/431 [React] 272샘의 React11 ( useState Hook )https://deahan.tistory.com/430 [React] 272샘의 React10 ( 레이아웃, children )https://deahan.tistory.c

deahan.tistory.com

 

까지도 벌써 읽었다면, 

이번시간엔 useEffect를 어케 쓰는지 조금 더 써보자.

프론트 프레임워크들은 기본적으로  CSR(Client Side Rendering)기반 

SPA(Single Page Application)를 법의 허락없이 감히 강요한다 하였다...

SPA를 구현하려면 AJAX 사용은  어쩔 수 없다. (금수저는 하루만에 AJAX달인이 되었다!)

 

AJAX를 써보려니  당근 Restful 서버의 필요가 또 어쩔 수 없다.

누군가는 여기서 Spring Boot를 기대할 수도 있다. (미안하당 아직 아님~~😝)

 

json-server 모듈을 이용한다면, 금방 연습용을 만들수 있으니, 만들어 보자

 

REACTSTUDY 폴더 아래에 myjsonserver라고 폴더를 만들자.

Terminal(cmd)에서  아래 명령어를 오타없이 잘치자.

cd myjsonserver
npm init -y 

 

package.json 파일이 생기면  고 안에 아래 내용을 추가하장.(import  사용을 위해서. 기억안나면 기억하삼!)

" type":"module",

 

아래 임시로 쓸 json형식 더미 데이터  파일을 myjsonserver 폴더에 만들자.(복사/붙여넣기)

db.json

{
  "friends": [
    { "id": "f01", "name": "경민", "age": 24, "avatar": "Leo",      "job": "기획" },
    { "id": "f02", "name": "미누", "age": 42, "avatar": "Luis",     "job": "개발" },
    { "id": "f03", "name": "병철", "age": 28, "avatar": "Sarah",    "job": "오류" },
    { "id": "f04", "name": "미영", "age": 30, "avatar": "Vivian",   "job": "운영"},
    { "id": "f05", "name": "선주", "age": 29, "avatar": "Maria",    "job": "감독"},
    { "id": "f06", "name": "나흠", "age": 34, "avatar": "Jocelyn",  "job": "관리"},
    { "id": "f07", "name": "원영", "age": 21, "avatar": "Riley",    "job": "노래"},
    { "id": "f08", "name": "선경", "age": 26, "avatar": "Brooklynn","job": "놀기"},
    { "id": "f09", "name": "리나", "age": 23, "avatar": "Sawyer",   "job": "댄스"},
    { "id": "f10", "name": "미선", "age": 26, "avatar": "Katherine","job": "런런"},
    { "id": "f11", "name": "선영", "age": 23, "avatar": "Eden",     "job": "그림" },
    { "id": "f12", "name": "오호", "age": 37, "avatar": "Brian",    "job": "설계" }
  ]
}

 

이제 Terminal(cmd)에 아래 명령어를 입력하여 보자.

npx json-server db.json --port 8220

아래와 같지 않다면 당신 손가락의 오류다.

브라우져 주소 표시줄에  아래 값들을 넣어서 결과를 확인해서 느낌을 얻자.

http://localhost:8220/

http://localhost:8220/friends

http://localhost:8220/friends/f05

 

만약 구글에서 "Chorme 웹 스토어" 로 검색 후  웹스토어에서 아래 처럼 "JSON Beautifier..." 검색후

해당 플러그인을 Chrome 확장프로그램에 추가한다면... 

JSON 형식 데이터를 아래 처럼 다양한 형식으로 예쁘게 볼수 있다.

 

혹  브라우져에 나온 결과가 당신의 호기심을 자극했다면, "db.json 파일을  랜덤데이터를 

이용해서 자동으로 만들수 있다면 아주 유용하겠는 걸"  머 그런 저런 생각을 했다면

2024.05.02 - [NodeJS] - Restful용 가짜 data 서비스 json-server 맹글기

글이 개발자 소양이 충분한 당신의 방문을 오래도록 오래전부터 기다린다.

 

확인했다면 서버가 돌도록 그대로 두고 vscode에서 cmd 터미널을 한개 더 열도록 하자

(아래 그림 참고하면 할 수 있을것이다.) 

 

만약 위 방식이 싫다면 vscode에서 File -> new Window로 vscode를 새창으로 1개 

더 열어서 작업하면 헷갈리지 않고 좋다. (개인적 추천 방법)

 

css가 일부 수정되어야 한다고 투덜 투덜 메세지가 비밀글로 와서 괜시리 맘이 쓰이는

관계로 요기서 다시 새로  REACTSTUDY 아래에  rfetchaxios 폴더를 만들어서 하자.

노파심에 나의 터미널을 복사해서 붙여본다.

D:\reactstudy>npm create vite@latest
Need to install the following packages:
create-vite@5.5.3 Ok to proceed? (y)

> npx
> create-vite

√ Project name: ... rfetchaxios
√ Select a framework: » React
√ Select a variant: » JavaScript

Scaffolding project in D:\reactstudy\rfetchaxios...

Done. Now run:

   cd rfetchaxios
   npm install
   npm run dev

D:\reactstudy>cd rfetchaxios
D:\reactstudy\rfetchaxios>npm install
D:\reactstudy\rfetchaxios>npm install -D @faker-js/faker
D:\reactstudy\rfetchaxios>npm run dev

 

초기 세팅이 같아지도록  index.css 와 App.css 파일안의 내용은  일단 전부 지워버리자.

그리고 체크 시작.

 

index.html

 
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <title></title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>
 

main.jsx

 
import { createRoot } from "react-dom/client";
import App from "./App.jsx";
import "./index.css";

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

App.jsx

 
import "./App.css";

function App() {
  return (
      <div>
        <h1>CSS는 알아서..</h1>
      </div>
  );
}

export default App;
 

요상태에서 빼먹지 말고 같이 가자. (나 자신에게 하는 말)

 

Friend.css

 
.friend {
    box-sizing: border-box;
    width: 150px;
    height: 250px;
    border: 5px groove blueviolet;
    display: inline-block;
    text-align: center;
    font-size: 1.5em;
    vertical-align: top;
  }
  h5 {
    margin: 0px;
    margin-bottom: 5px;
  }
 

 

 

Friend.jsx

 
import "./Friend.css";
import PropTypes from "prop-types";
import { faker } from "@faker-js/faker/locale/ko";

//Props 타입 정의
Friend.propTypes = {
  fid: PropTypes.string,
  name: PropTypes.string,
  age: PropTypes.number,
  avatar: PropTypes.string,
  job: PropTypes.string,
};


function Friend({ fid, name, age, avatar, job }) {
  if (!fid) {
    fid = `f${faker.number.int({ min: 100, max: 999 })}`;
    name = faker.person.firstName();
    age = faker.number.int({ min: 20, max: 99 });
    avatar = faker.person.firstName();
    job = faker.person.jobTitle().split(" ")[1];
  }

  console.log("체크:", fid, name, age, avatar, job);

  return (
    <div className="friend">
      <img src={`${avatarURL}${avatar}`} alt="아바타" />
      <h5>{name}</h5>
      <h5>{age}</h5>
      <h5>{job}</h5>
    </div>
  );
}

export default Friend;
 

 

 

Container.css

 
.container {
    width: 600px;
    min-height: 420px;
    border: 1px solid pink;
    margin: 50px auto;
    text-align: center;

  }
  .minux {
    font-size: 4em;
    line-height: 130%;
    background-color: black;
    color:yellow;
  }
 

 

Container.jsx

 
import "./Container.css";
import Friend from "./Friend";
function Container() {
  return (
    <div className="container">
      <h1>경미니 베.푸(Very Proud)들</h1>
      <Friend />
      <Friend />
      <Friend />
      <Friend />
      <div className="minux">&copy;MINUX만만/div>
    </div>
  );
}

export default Container;
 

 

 

App.jsx

 
import "./App.css";
import Container from "./Container";

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

export default App;
 

 

결과 화면은  faker를 썼기 때문에 틀만 같고 내용은 다를 수 있을지어다.

Container.jsx   비동기 AJAX Promise를 리턴하는 fetch를 넣어 아래처럼 수정해 보자.

import "./Container.css";
import Friend from "./Friend";
function Container() {
  let kmFriends = [];
  fetch("http://localhost:8220/friends").then((response) => {
    response.json().then((friends) => {
      console.log("체크:", friends);
      kmFriends = friends;
    });
  });

  return (
    <div className="container">
      <h1>경미니 베.푸(Very Proud)들</h1>
      {kmFriends.length != 0 ? <Friend /> : <h1>친구 없어요</h1>}
      <div className="minux">&copy;MINUX 만만세</div>
    </div>
  );
}

export default Container;

결과 화면을  눈으로 확인한다면

당근 Friend  아니고, 친구없어요가 뜬다. console.log에는 값이 잘 찍히지 않을 수 없다.

비동기니까.. fetch가 값을 가져오는 동안 화면이 먼저 그려졌다.(비동기 알지요?)

 

요걸 나오게 하려면, useEffect와 useState 가 다 필요하다.

Container.jsx 를 아래처럼 수리해서 실행해 보자

 
import { useEffect, useState } from "react";
import "./Container.css";
import Friend from "./Friend";
function Container() {
  const [friends, setFriends] = useState([]);

  useEffect(() => {
    fetch("http://localhost:8220/friends").then((response) => {
      response.json().then((friends) => {
        console.log("체크:", friends);
        setFriends(friends);
      });
    });
  }, []);

  return (
    <div className="container">
      <h1>경미니 베.푸(Very Proud)들</h1>
      {friends.length != 0 ? (
        friends.map((frd) => (
          <Friend
            key={frd.id}
            fid={frd.id}
            name={frd.name}
            age={frd.age}
            avatar={frd.avatar}
            job={frd.job}
          />
        ))
      ) : (
        <h1>친구없어요</h1>
      )}
      <div className="minux">&copy;MINUX 만만세</div>
    </div>
  );
}

export default Container;
 

결과는 아래와 같을것이다.

 

흐름 정리를 한번 해보면...

1. 리액티브 변수 friends 초기값 빈배열이어서 

2.  JSX 컴포넌트는 <h1>친구 없어요</h1>

3.  useEffect실행, 두번째 매개변수 []라서 딱 한번만 실행

4,  fetch로 값을 가져와, setFriends호출, 리액티브 변수값 변경

5,  return 되는 jsx 컴포넌트 다시 그리기, 이땐 friends값 존재

 

결론적으로 친구없어요 이었다가 화면이 다시 그려지는건데, 넘 빨리 다시 그려

안보인다.~~ ㅋㅋ. 느낌이 와야만 한다.

 

useEffect 훅(hook) 함수의 두번째 매개변수를 [] 에서 [friends]로 바꾸면 무슨 일이 일어날까?

한번 꼭 해보았으면 좋겠다. ~~ 그리고 꼭  console.log를 보아야 한다.

결과화면은 분명 당신에게 아무일도 없는 것처럼 잔잔히 속이려 들것이다.

 

결과화면에게 속은 걸 모르겠다면, 아래 소스를 가지고 해보길 바란다.

Container.jsx

 
import { useEffect, useState } from "react";
import "./Container.css";
import Friend from "./Friend";
function Container() {
  const [friends, setFriends] = useState([]);

  useEffect(() => {
    fetch("http://localhost:8220/friends").then((response) => {
      response.json().then((friends) => {
        console.log("체크:", friends);
        setFriends(friends.map(friend=>{
            friend.avatar = `${friend.avatar}${Math.floor(Math.random()*100)}`
            return friend;
      }));
      });
    });
  }, [friends]);

  return (
    <div className="container">
      <h1>경미니 베.푸(Very Proud)들</h1>
      {friends.length != 0 ? (
        friends.map((frd) => (
          <Friend
            key={frd.id}
            fid={frd.id}
            name={frd.name}
            age={frd.age}
            avatar={frd.avatar}
            job={frd.job}
          />
        ))
      ) : (
        <h1>친구없어용</h1>
      )}
      <div className="minux">&copy;MINUX 만만세</div>
    </div>
  );
}

export default Container;
 

어쩌면 이 상태(state)관리가 당신을 힘들게 할 지도 몰랐는데,

다행히 이 부분이  요래 조래 여러가지 모듈들이 나와서 경쟁하다가 최근

결정적 우세종(?? 지금은 안 알려줄거임~~ ㅋ)이 나와서 이긴 것 같으니

걱정따위는 분리수거말고 그냥 태워서 흔적을 없애도 되겠다.

 

앞으로 Promise를 리턴하는 fetch 나 axios 쓸꺼이기 때문에 혹 아직 Promise를 모른다면

2024.01.08 - [자바스크립트] - Promise(약속) 모르면 바보옹(비동기)

글을 꼬옥 읽고, 연습도 하고 다시 만나길 기대해본다.

 

출처 : https://e-7-e.tistory.com/262