문제: 정해진 예산 5만원이 있고 어떠한 커피를 주문하는지에 따라서 해당 메뉴가 카운팅 되고,
총 가격 버튼을 누를 경우 총 얼마를 지불해야하는지, 거스름돈이 출력된다.
import React, { useState } from "react";
function App() {
return (
<div className="App">
<Menu />
</div>
);
}
// -----------------------------함수형 컴포넌트 분리
const Menu = () => {
const [data, setData] = useState([]);
const parentFunction = (pass) => {
console.log(pass);
const newData = [...data];
newData.push(pass);
setData(newData);
};
return (
<>
<MenuList
price="4100"
menu="아메리카노"
parentFunction={parentFunction}
/>
<MenuList price="4600" menu="카페라떼" parentFunction={parentFunction} />
<MenuList
price="5100"
menu="캬라멜 마끼아또"
parentFunction={parentFunction}
/>
<button>총 가격 </button> :<p>남는 돈: </p>
</>
);
};
const MenuList = ({ price, menu, parentFunction }) => {
const [count, setCount] = useState(0);
const handleClickAdd = () => {
setCount((current) => current + 1);
console.log(count);
parentFunction({ price, menu, count });
};
const handleClickDelete = () => {
setCount((current) => (current > 0 ? current - 1 : 0));
console.log(count);
};
return (
<p>
{`${price}원 ${menu}: ${count}`}
<button onClick={handleClickAdd}>추가</button>
<button onClick={handleClickDelete}>감소</button>
</p>
);
};
export default App;
1) 문제점
더해진 값에 따라서 버튼을 클릭할 때마다 화면에는 증가하는 값이 잘 출력이 된다.
하지만, count를 바로 찍어도 더해진 값이 출력되지 않는다.
useState의 setCount는 비동기로 동작하기 때문에 그러한 것으로 보인다.
const handleClickAdd = () => {
setCount((current) => current + 1); // setCount(count + 1);
console.log(count);
parentFunction({ price, menu, count });
};
해당 값(count)이 변할때를 감지하는useEffect()
를 추가하여 해결
import React, { useState, useEffect } from "react";
function App() {
return (
<div className="App">
<Menu />
</div>
);
}
// -----------------------------함수형 컴포넌트 분리
const Menu = () => {
const MONEY = 50000; // 지정한 회비
const [data, setData] = useState([]);
const [payMoney, setPayMoney] = useState(0);
const [change, setChange] = useState(0);
const handleClickTotal = (e) => {
//총 가격 계산
const total = data.reduce((pre, cur) => {
return pre + cur.price * cur.count;
}, 0);
//가격에 따라서 총 금액과 남는돈 set
setPayMoney(total);
setChange(MONEY - total);
};
useEffect(() => {
console.log("Menu useEffect", data);
}, [data]);
const handleClick = (pass) => {
//console.log("pass data:", pass);
const newData = [...data];
const exist = newData.find((item) => pass.menu === item.menu);
//같은 데이터가 존재하지 않는다면 넣어주고
if (!exist) {
newData.push(pass);
}
//같은 데이터가 존재한다면 count값만 갱신
else {
newData.forEach((item, index) => {
if (item.menu === pass.menu) {
newData[index].count = pass.count;
}
});
}
setData(newData);
};
return (
<>
<MenuList price="4100" menu="아메리카노" handleClick={handleClick} />
<MenuList price="4600" menu="카페라떼" handleClick={handleClick} />
<MenuList price="5100" menu="캬라멜 마끼아또" handleClick={handleClick} />
<button onClick={handleClickTotal}>총 가격 </button> : {payMoney}
<p>남는 돈: {change} </p>
</>
);
};
const MenuList = ({ price, menu, handleClick }) => {
const [count, setCount] = useState(0);
//useEffect로 변경하여 부모컴포넌트에 데이터를 전달
useEffect(() => {
handleClick({ price, menu, count });
}, [count]);
//이것도 왜 2번호출되지 ?
// useEffect(() => {
// console.log("useEffect : ");
// }, []);
const handleClickAdd = () => setCount(count + 1);
const handleClickDelete = () =>
setCount((current) => (current > 0 ? current - 1 : 0));
return (
<p>
<span>{`${price}원 ${menu}: `}</span>
<span>{`${count}`}</span>
<button onClick={handleClickAdd}>추가</button>
<button onClick={handleClickDelete}>감소</button>
</p>
);
};
export default App;
2) 문제점 / useEffect 의 동작
useEffect는 랜더링 될 때와 값이 변경될때 호출이되는 것으로 알고있는데,
처음 랜더링될때 이것이 2번 호출되는 것으로 보이며,
<MenuList>
의 마지막 요소가 data로 미리 들어가면서 한번더 useEffect가 호출되는 문제점을 볼 수 있었다.
콘솔로 찍어보지 않았을 때는 제대로 동작하는걸로 착각할 수 있다.
현재 코드는 뭔가 이상해보인다.