[Mini Project] Monster - Funtion

김찬영·2021년 1월 3일
1

Mini Project

목록 보기
2/4
post-thumbnail

구현하는 기능과 배우는 컨셉

간단한 레이아웃 생각해보기
usehistory
useEffect , deps
useParams

레이아웃 생각해보기

간단하게 레이아웃을 구성해보았다. 아직은 머릿속으로 확 들어오지않아서 정리할때 작성하곤한다.

최상단 부모 Monster.js

내가 리액트에서 제일 리팩토링 많이했던부분이 state관리하는 시점과 관리하는 방법이다. 특정 자식에서 사용하는 state를 제외하고는 state는 부모가 관리하는게 state관리에 용이하다. 하지만 리덕스를 사용하면 고민이 해결되겠지만

  • API GET
  • SearchBox onChange data state 관리
  • Data && SearchData Filtering Props전달

---Monster.js----
import React, {useState, useEffect} from 'react';
import SearchBox from './Components/SearchBox/SearchBox';
import CardList from './Components/CardList/CardList';
import './Monsters.scss';

function Monsters() {
  const [monsters, setMonsters] = useState([]);
  const [userInput, setUserInput] = useState('');

  useEffect(() => {
    getMonsters();
  }, []);

  // 데이터 로딩

  const getMonsters = () => {
    const API = 'https://jsonplaceholder.typicode.com/users';
    fetch(API)
      .then((res) => res.json())
      .then((result) => setMonsters(result));
  };

  // SearchBox 에 props로 넘겨줄 handleChange 메소드 정의
  const handleChange = (e) => {
    setUserInput(e.target.value);
  };

  return (
    <div className="Monsters">
      <h1>컴포넌트 재사용 연습!</h1>
      <SearchBox handleChange={handleChange} />
      <CardList
        monsters={monsters.filter((el) => {
          return el.name.toLowerCase().includes(userInput.toLocaleLowerCase());
        })}
      />
    </div>
  );
}

export default Monsters;

CardList

  • Card들을 맵핑해주어 CardList들을 보여주는 컴포넌트
  • Filtering된 Data들중 Card 컴포넌트에서 필요한 id name email을 props전달

function CardList({monsters}) {
  return (
    <div className="card-list">
      {monsters.map((e) => {
        return <Card id={e.id} name={e.name} email={e.email} />;
      })}
    </div>
  );
}

export default CardList;

Card

  • Filtering된 Card의 UI를 작성한 컴포넌트
  • Props로 전달된 ID, EMAIL, NAME 사용
  • 특히, IMG SRC에서는 ID값을 활용해서 각각의 Card img를 보여줌
  • Card Click시 CardDetail 컴포넌트로 이동

---Card.js----

import React from 'react';
import {useHistory} from 'react-router-dom';

function Card({id, name, email}) {
  let history = useHistory();
  function gotoDetail() {
    history.push(`/monsters/detail/${id}`);
  }

  return (
    <div className="card-container" onClick={gotoDetail}>
      <img src={`https://robohash.org/${id}?set=set2&size=180x180`}></img>
      <h2> {name}</h2>
      <p> {email}</p>
    </div>
  );
}

export default Card;

CardDetail

  • Route 설정한 /monsters/detail/${id} id key 값 이용
  • useParams를 사용해서 match.params 객체를 접근
  • useEffect를 이용해서 https://jsonplaceholder.typicode.com/users/의 각 해당 id으 카드데이터 업데이트 시키기
  • usehistroy를 이용해서 Route 이용하여 prev, next, back btn 만들기

---CardDetail--

import React, {useState, useEffect} from 'react';
import {useParams, useHistory} from 'react-router-dom';
import Card from './Components/Card/Card';
import './MonsterDetail.scss';

function MonsterDetail() {
  let {id} = useParams();
  let history = useHistory();
  let [data, setData] = useState([]);

  useEffect(() => {
    fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
      .then((res) => res.json())
      .then((res) => {
        setData(res);
      });
  }, [id]);

  const goToMonstersList = () => {
    history.push('/');
  };
  const goToPrevious = () => {
    history.push(`/monsters/detail/${id - 1}`);
  };
  const goToNext = () => {
    history.push(`/monsters/detail/${+id + 1}`);
  };

  return (
    <div className="url-parameters">
      <div className="btn-wrapper">
        <button onClick={goToMonstersList}>Back to Monsters List</button>
      </div>
      <Card id={data.id} name={data.name} email={data.email} />
      <div className="btn-wrapper">
        <button onClick={goToPrevious}>Previous</button>
        <button onClick={goToNext}>Next</button>
      </div>
    </div>
  );
}

export default MonsterDetail;

useParams는 Card에서 접근한 URL를 match.params 객체로 접근 할 수있다. id를 활용해서 useEffect에서 fetch로 받아온 데이터에 변수 id를 넣어준다. 즉, Card를 클릭할때마다 해당하는 Card의 id를 useParams로 받아와서 패치하면 그에 해당하는 data를 setData에 관리해준다.

useEffect의 두번째 인자로 [id]를 왜 사용할까! 🧏‍♂️

class형 함수에서 우리는 componentdidupdate를 사용했다. 그 이유가 무엇일까?

Next, Prev 버튼을 누를때 id값이 변하지만 데이터는 변하지않기때문이다. 저기서 useEffect의 두번째 인자가 빈배열이면 처음 한번밖에 실행되지않아서 업데이트가 되지않는다.

예를들어, CardList에서 클릭한 Card가 id값이 1번인 Card라고 생각해보자. 그럼 CardDetail/1 페이지로 이동한다. 이미 딱한번 useEffect가 실행된다. 이후, prev, next 버튼을 누르면 id값이 변하지만 더이상 useEffect는 실행되지않는다. 그래서 업데이트가 되지않는다!!

업데이트를 해보자! 🙆‍♂️

업데이트를 하려면 두번째인자 배열안에 클릭했을때 변하는 값을 넣어줘야한다. 여기서는 바로 id가 그에해당한다. 아까 예를 이어서 생각해보자, 1번을 클릭하면 지금 useEffect에 있는 id값은 1 이되고 Next 버튼을 누르면 id는 2로 변한다. 즉 1과 2는 다르므로 업데이트가 되고 무한루프가 걸리지않는다. class형에서는 조건문이 있어야했다.

componentDidUpdate(prevProps, _) {
    if (prevProps.match.params.id !== this.props.match.params.id) {
      this.getData();
    }
  }

하지만 이동작이 [id] 이 한줄로 표현이 된다는 것이다! 이리하여 함수형으로도 간단하게 Monster기능을 구현했다.

profile
Front-end Developer

0개의 댓글