크게 4가지 파트로 나뉠 수 있습니다
1. import
2. 변수 선언
3. 함수 선언
4 JSX 문법
import './App.css';
import React, { useEffect, useState } from "react"; //react 내장함수 useEffect,useState를 사용하겠다 선언
import Recipe from './Recipe'; //Recipe import
./App.css import 합니다, 내장함수 useEffect, useState 를 호출합니다, ./Recipe 를 호출합니다
const APP_ID = "2b215e76bde";
const APP_KEY = "ec75e604b3fcb19322b51f9ed9bc9906bcc";
const [recipes, setRecipes] = useState([]);// recipes 초기화, 아무값 들어 있지 않습니다
const [search, setSearch] = useState('');//search 초기화, 아무값 들어 있지 않습니다.
const [query, setQuery] = useState('chicken'); //query 초기화, chicken 이 들어 있습니다
//useEffect 는 웹브라우저가 재랜더링 할때마다 실행됩니다 -> 안좋음
//useEffect 에 dependency ([]) 를 추가해서 웹 브라우저 실행시 단 한번만 실행되게 합니다
//useEffect 에 [변수] 를 넣어서, 변수가 바뀔때마다 재 랜더링이 실행되게 합니다
api id 랑 key 는 유효하지 않습니다. 변수 선언 파트 입니다, recipes랑 search 가 초기값이 없는 이유
1. recipes 는 setRecipes의 인자값을 recipes 에 넣습니다. 그 인자값은 api로 가져온 데이터 입니다. (getRecipes 에서 확인)
2. search 는 input 태그 text 입니다. 초기에 빈 값인데, 사용자가 글을 입력하면 value 로써 값이 던져집니다. (getSearch 에서 확인)
useEffect(() => {
getRecipes(); //웹브라우저 실행시 최초 1회 실행됩니다
}, [query]);//초기 query 는 chicken 입니다,
//비동기식을 동기식으로 바꾸다.
//웹브라우저 실행때 한번, query -> 검색창에 입력되고 버튼을 누르고 나면 실행됩니다
const getRecipes = async () => {
const response = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`); //웹 브라우저한테 api를 받을때까지 뒷 로직을 실행시키지 않게 시킵니다
const data = await response.json(); //받은 데이터를 json 형태로 저장합니다
//setRecipes 안에 넣음으로써 recipes 가 data.hits를 가지고 있다
setRecipes(data.hits); //json 데이터에 hits 키값을 주고 value 를 가져옵니다
}
//input 태그에 입력된 인자값이 e 로 갑니다. setSearch 에 태그에 입력,삭제된 값들이 출력됩니다
const updateSearch = e => {
setSearch(e.target.value);//초기값이 없었던 search 가 e.target.value 로 채워집니다.
}
const getSearch = e => {//submit 버튼을 누르면 onSubmit 속성때문에 getSearch 함수가 실행됩니다. 받은 인자값에 페이지 이동을 하지 않기위해 preventDefault()가 있습니다
e.preventDefault();
setQuery(search);//초기 query 였던 chicken 이 검색에 따라 달라집니다 //search 는 input 의 value 입니다, 초기값 chicken 이 input 으로부터 들어온 value 로 채워집니다
setSearch('');//검색 버튼을 한번 누르고 난뒤 입력한 값이 사라집니다
}
함수 선언파트 입니다. useEffect 는 웹브라우저 실행시 최소 1번 실행으로 chicken 레시피가 호출됩니다. query 가 바귈때마다 레시피는 바귑니다. query 는 setQuery 의 인자값이 바뀔때 바귀는데 form 태그에서 버튼을 누르면 onSubmit 이 작동해서 getSearch 함수 호출됩니다.
<div className="App">
{/* submit 버튼을 누를때 마다 onSubmit 에 있는 getSearch가 실행됩니다 onSubmit 은 호출 될때마다 웹 브라우저 새로고침이 발생하기 때문에 preventDefault 로 잡아줘야 합니다 */}
<form onSubmit={getSearch} className="search-form">
{/* input태그에 변화가 있을때마다(글자입력,삭제) updateSearch 함수가 실행됩니다 */}
{/* 자바스크립트 값을 jsx 내부에서 사용할 때는 중괄호로 감싸주어야 한다 */}
<input className="search-bar" type="text" value={search} onChange={updateSearch} />
<button className="search-button" type="submit">Search</button>
</form>
{/* map 메소드는 recipes 로 받아온 모든 데이터를 배열"[]" 에 넣겠다 입니다 */}
<div className="recipes">
{recipes.map(recipe => (
<Recipe
//아랫 키 값들은 Recipe.js 로 가서 인자값이 됩니다 key 라는 유니크 값이 없다면 콘솔에 에러가 뜹니다(고유값 주라고 )
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
/>
))};
</div>
</div>
JSX 파트 입니다. 함수 호출 2군데 있고, 텍스트박스에 글을 입력하고 버튼을 누르면 다른 레시피를 찾습니다. 받아온 레시피를 재정렬 하기 위해서 map 메소드를 사용합니다. 해당 인자값recipe 은 Recipe.js 의 인자값으로 넘어 갑니다 key 가 없다면 콘솔창 워닝이 발생합니다. label 이 각 레시피의 고유값이라 넣었습니다. 아무 중복되지 않는 값만 넣는다면 워닝은 사라집니다
Recipe.js 파트 입니다
import React from 'react';
import style from './recipe.module.css';
const Recipe = ({ title, calories, image, ingredients }) => {
return (
<div className={style.recipe}>
<h1>{title}</h1>
<ol>
{ingredients.map(ingredient => (
<li>{ingredient.text}</li>
))}
</ol>
<p>{calories}</p>
<img className={style.image} src={image} alt="" />
</div >
);
}
export default Recipe;
넘어온 인자값이 보입니다. div className 에 recipe.module.css 로 스타일링 해서 넘겨 줬습니다. 넘어온 레시피는 map으로 재정렬 해서 번호를 매겨줬습니다.
{/ onChange 가 없으면 value 는 항상 empty 라서 input 태그에 글을 적을 수 없습니다 /}