React

 

 

초급자를 위해 준비한
[웹 개발, 프론트엔드] 강의입니다.

리액트를 가장 쉽고 빠르게 배울 수 있는 리액트 입문 강의입니다. 토이 프로젝트를 만들면서 개념과 실전 감각을 익히고 배포까지 3시간 만에 완성하는 알짜 강의! 초급, 중급, 고급으로 구성된 시리즈의 첫 번째 강의입니다 :)

✍️
이런 걸
배워요!

리액트 개발

프런트엔드 개발

웹 개발

나만의 토이프로젝트

백엔드 연동

 

강의 :

https://www.inflearn.com/course/만들면서-배우는-리액트-기초#

 

 

 

https://github.com/milooy/cat-jjal-maker/blob/main/answers/2-setup.html

 

https://github.com/braverokmc79/cat-short-app

https://github.com/braverokmc79/react-cat-short-app

 

 

 

[6].리액트 앱에 숨 불어넣기

 

 

 

27. 실제 고양이 데이터 받아오기 -  fetch, Open API

 

강의:

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102201&category=questionDetail&tab=curriculum

 

 

    <script>


     const getCatData=async () =>{
        return await fetch("https://cataas.com/cat?json=true")
        .then((response) => response.json())
        .then((data) => data);
      }
      
     async  function  geCats(){
        const data =await getCatData();
        console.log("data  : " ,data);
      }

      geCats();
       
    </script>

 

콘솔창 출력

  1. createdAt: "2022-05-01T21:03:13.331Z"
  2. file: "626ef5917f254a0017b56506.gif"
  3. mimetype: "image/gif"
  4. owner: "null"
  5. size: 1982059
  6. tags: (5) ['fall', 'snow', 'slow motion', 'ears', 'gif']
  7. updatedAt: "2022-10-11T07:52:32.684Z"
  8. url: "/cat/vjQhaUpsIcSMOthc"
  9. validated: true
  10. _id: "vjQhaUpsIcSMOthc"
  11. [[Prototype]]: Object

 

 

 

 

 

 

 

 

 

 

 

 

28.고양이 데이터 내 앱에 연동하기

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102202&category=questionDetail&tab=curriculum

 

     //Form 폼 시작
     const Form=({updateMainCat })=>{
        const [value, setValue] =React.useState("");
       const includesHangul = (text) => /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/i.test(text);
       const [errorMessage  , setErrorMessage] =React.useState("");


       function handleInputChange(e){
          const useValue=e.target.value;
          setErrorMessage("");
          if(includesHangul(useValue)){
            setErrorMessage("한글은 입력할 수 없습니다.");
          }
          setValue(e.target.value.toUpperCase()) ;
       }

       function handleFormSubmit(e){
          e.preventDefault();
          setErrorMessage("");
          if(value===''){
            setErrorMessage("빈값으로 만들 수 없습니다.");
            return;
          }
          //업데이트 하기
          updateMainCat(value);
        }

        return (
          <form onSubmit={handleFormSubmit}>
            <input type="text" name="name"   placeholder="영어 대사를 입력해주세요"  
                value={value}
                onChange={handleInputChange}
            />
             
            <button type="submit">생성</button>
            <p style={{color:"red"}}>{errorMessage}</p>
          </form>
        );
    }
   //Form 폼 끝

 

 

 

    const fetchCat = async (text) => {
        const OPEN_API_DOMAIN = "https://cataas.com";
        const response = await fetch(`${OPEN_API_DOMAIN}/cat/says/${text}?json=true`);
        const responseJson = await response.json();
        return `${OPEN_API_DOMAIN}/${responseJson.url}`;
    };

    


   async function updateMainCat(value){
          const nextCounter =counter+1;
          setCounter(nextCounter);
          jsonLocalStorage.setItem("counter",nextCounter);
          const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
          //setMainCardImgSrc(mainImageSrcArr[nIndex]);
          const img = await fetchCat(value);
          setMainCardImgSrc(img);
        }



 

 

 

 

 

 

 

29. 컴포넌트 생성시 고양이 데이터 받아오기 - useEffect

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102203&category=questionDetail&tab=curriculum

 

 

~


        const [mainCardImgSrc, setMainCardImgSrc] =React.useState("");
       

        async function setInitialCat(){
          const newCat=await fetchCat("First cat ");
          console.log(newCat);
          setMainCardImgSrc(newCat);
        }


        React.useEffect(()=>{
            setInitialCat();
        }, []);



~

 

 

 

 

 

 

 

 

 

 

 

 

30. useEffect 의 정체

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102204&category=questionDetail&tab=curriculum

 

 

 

 

 

31. 조건부 렌더링

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102205&category=questionDetail&tab=curriculum

 

 

  const MainCard=({alreadyFavorite, mainCardImgSrc, onHeartClick ,alt,width })=>{
        const EMPTY_HEART = "????";
        const FULL_HEART = "????";    

        const heartIcon =alreadyFavorite ? FULL_HEART:  EMPTY_HEART;
        
        return  (
          <div className="main-card">
          <img
            src={mainCardImgSrc}
            alt={alt}
            width={width}
          />
          <button onClick={onHeartClick}  >{heartIcon}</button>
        </div>
        );
      }


      const App=()=>{
        const CAT1 = "https://cataas.com/cat/HSENVDU4ZMqy7KQ0/says/react";
        const CAT2 = "https://cataas.com/cat/BxqL2EjFmtxDkAm2/says/inflearn";
        const CAT3 = "https://cataas.com/cat/18MD6byVC1yKGpXp/says/JavaScript";
        const cats= [CAT1,CAT2];
        const [favorites , setFavorites]=React.useState(jsonLocalStorage.getItem("favorites") ||  []);
        const [counter ,setCounter ] =React.useState(jsonLocalStorage.getItem("counter"));
        const [mainCardImgSrc, setMainCardImgSrc] =React.useState("");
        const  alreadyFavorite =  favorites.includes(mainCardImgSrc);

        async function setInitialCat(){
          const newCat=await fetchCat("First cat ");
          console.log(newCat);
          setMainCardImgSrc(newCat);
        }
   

        React.useEffect(()=>{
            setInitialCat();
        }, []);



~

   return(
          <div>
            <Title>{counter}번째 고양이 가라사대</Title>,
            <Form   updateMainCat={updateMainCat} />
            <MainCard alreadyFavorite={alreadyFavorite} mainCardImgSrc={mainCardImgSrc}  onHeartClick={onHeartClick} alt="alt"   width="400" />
            <Favorites  favorites={favorites} />
          </div>
        )



 

 

 

 

 

 

 

 

32.퀴즈풀이

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102206&category=questionDetail&tab=curriculum

 

        const counterTitle =counter===null ? "" : counter +"번째 ";

        return(
          <div>
            <Title>{counterTitle} 고양이 가라사대</Title>,

 

 

 

 

 

 

 

 

 

 

 

33. setState 더 알아보기-함수, 지연초기화

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102207&category=questionDetail&tab=curriculum

 

        const [favorites , setFavorites]=React.useState(()=>{
            return jsonLocalStorage.getItem("favorites") ||  [];
        });
        const [counter ,setCounter ] =React.useState(()=>{
          return jsonLocalStorage.getItem("counter")
        });

 

       async function updateMainCat(value){
          //const nIndex= Math.floor(Math.random()* mainImageSrcArr.length);
          //setMainCardImgSrc(mainImageSrcArr[nIndex]);
          const img = await fetchCat(value);
          setMainCardImgSrc(img);

        
          setCounter((prev)=>{
            const nextCounter =prev+1;
            jsonLocalStorage.setItem("counter",nextCounter);
            return nextCounter;
          });
         
        }

 

 

 

 

 

 

 

 

 

 

 

 

[7].실무 개발환경 만들기

 

 

34. create-react-app-실무 개발환경 만들기

 

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102209&category=questionDetail&tab=curriculum

 

 


npx create-react-app cat-jjal-maker-cra


 

 

 

 

 

 

 

35. create-react-app 폴더 구조 뜯어보기2

 

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102210&category=questionDetail&tab=curriculum

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

36. 지금까지 만든 앱 create-react-app 으로 옮기기

 

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102211&category=questionDetail&tab=curriculum

 

App.css

body {
  text-align: center;
}
.main-card button {
  position: relative;
  left: -45px;
  bottom: 15px;
}
.favorites {
  list-style: none;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 15px;
}
.favorites img {
  width: 150px;
}
form{
  margin-bottom: 20px;
}

 

 

App.js

import logo from "./logo.svg";
import "./App.css";
import { useEffect, useState } from "react";
import { Title } from "./components/Title";
import Form from "./components/Form";
import MainCard from "./components/MainCard";
import Favorites from "./components/Favorites";

const App = () => {
  const [loading, setLoading] = useState(false);

  const jsonLocalStorage = {
    setItem: (key, value) => {
      localStorage.setItem(key, JSON.stringify(value));
    },
    getItem: (key) => {
      return JSON.parse(localStorage.getItem(key));
    },
  };

  const fetchCat = async (text) => {
    const OPEN_API_DOMAIN = "https://cataas.com";
    const response = await fetch(
      `${OPEN_API_DOMAIN}/cat/says/${text}?json=true`
    );

    const responseJson = await response.json();
    return `${OPEN_API_DOMAIN}/${responseJson.url}`;
  };

  const [favorites, setFavorites] = useState(() => {
    return jsonLocalStorage.getItem("favorites") || [];
  });

  const [counter, setCounter] = useState(() => {
    return jsonLocalStorage.getItem("counter");
  });
  const [mainCardImgSrc, setMainCardImgSrc] = useState("");
  const alreadyFavorite = favorites.includes(mainCardImgSrc);

  async function setInitialCat() {
    const newCat = await fetchCat("First cat ");
    console.log(newCat);
    setMainCardImgSrc(newCat);
  }

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

  function onHeartClick() {
    const nextFavorites = [...favorites, mainCardImgSrc];
    setFavorites(nextFavorites);
    jsonLocalStorage.setItem("favorites", nextFavorites);
  }

  async function updateMainCat(value) {
    setLoading(true);
    const img = await fetchCat(value);
    setMainCardImgSrc(img);

    setCounter((prev) => {
      const nextCounter = prev + 1;
      jsonLocalStorage.setItem("counter", nextCounter);
      setTimeout(() => {
        setLoading(false);
      }, 500);

      return nextCounter;
    });
  }

  const counterTitle = counter === null ? "" : counter + "번째 ";

  return (
    <div>
      <Title>{counterTitle} 고양이 가라사대</Title>,
      <Form updateMainCat={updateMainCat} loading={loading} />
      <MainCard
        alreadyFavorite={alreadyFavorite}
        mainCardImgSrc={mainCardImgSrc}
        onHeartClick={onHeartClick}
        alt="alt"
        width="400"
      />
      <Favorites favorites={favorites} />
    </div>
  );
};

export default App;

 

 

 

components/CatItem.js

import React from "react";

export const CatItem = (props) => {
  return (
    <>
      <li>
        <img src={props.img} style={{ width: "150px" }} alt="props.img" />
      </li>
    </>
  );
};

 

 

 

 

components/Favorites.js

import React from "react";
import { CatItem } from "./CatItem";

const Favorites = ({ favorites }) => {
  if (favorites.length === 0) {
    return <div>사진 위 하트를 눌러 고양이 사진을 저장해봐요!</div>;
  }

  return (
    <ul className="favorites">
      {favorites.map((cat, index) => (
        <CatItem img={cat} key={index} />
      ))}
    </ul>
  );
};

export default Favorites;

 

 

 

 

components/Form.js

import React, { useState } from "react";

const Form = ({ updateMainCat, loading }) => {
  const [value, setValue] = useState("");
  const includesHangul = (text) => /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/i.test(text);
  const [errorMessage, setErrorMessage] = React.useState("");

  function handleInputChange(e) {
    const useValue = e.target.value;
    setErrorMessage("");
    if (includesHangul(useValue)) {
      setErrorMessage("한글은 입력할 수 없습니다.");
    }
    setValue(e.target.value.toUpperCase());
  }

  function handleFormSubmit(e) {
    e.preventDefault();
    setErrorMessage("");
    if (value === "") {
      setErrorMessage("빈값으로 만들 수 없습니다.");
      return;
    }
    //업데이트 하기
    updateMainCat(value);
  }

  return (
    <form onSubmit={handleFormSubmit}>
      <input
        type="text"
        name="name"
        placeholder="영어 대사를 입력해주세요"
        value={value}
        onChange={handleInputChange}
      />

      {loading ? (
        <button type="button">로딩중</button>
      ) : (
        <button type="submit">생성</button>
      )}

      <p style={{ color: "red" }}>{errorMessage}</p>
    </form>
  );
};

export default Form;

 

 

 

 

components/MainCard.js

import React from "react";

const MainCard = ({
  alreadyFavorite,
  mainCardImgSrc,
  onHeartClick,
  alt,
  width,
}) => {
  const EMPTY_HEART = "????";
  const FULL_HEART = "????";

  const heartIcon = alreadyFavorite ? FULL_HEART : EMPTY_HEART;

  return (
    <div className="main-card">
      <img src={mainCardImgSrc} alt={alt} width={width} />
      <button onClick={onHeartClick}>{heartIcon}</button>
    </div>
  );
};

export default MainCard;

 

 

 

 

components/Title.js

 

import React from "react";

export const Title = (props) => {
  return <h1>{props.children}</h1>;
};

 

 

 

 

 

 

 

 

 

 

 

 

37.빌드한 결과물 github pages로 배포하기

 

 

강의 :

 

https://www.inflearn.com/course/lecture?courseSlug=만들면서-배우는-리액트-기초&unitId=102212&category=questionDetail&tab=curriculum

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

손 안 대고 코 풀기 , 일을 매우 쉽게 해치운다는 뜻.

댓글 ( 4)

댓글 남기기

작성