Language/React
[React] 예시 9. 이전 작업 node.js 환경 세팅
print(blue)
2024. 6. 4. 09:02
https://print-blue.tistory.com/201
코드 옮기기
node.js 환경에서는 자동으로 react 를 가져올 수 없어서 import 해줘야 함
import React from 'react';
이미지 폴더가 없어서 이미지가 깨지는데 public 폴더에 복사 !
css 추가
# p240603\first-my-app\src\index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
/* 스타일 적용 */
body {
text-align: center;
}
form {
margin-bottom: 20px;
}
.main-card button {
position: relative;
left: -45px;
bottom: 15px;
}
.favorites {
list-style: none;
display: flex;
gap: 15px;
justify-content: center;
flex-wrap: wrap;
}
.favorites img {
width: 150px;
}
컴포넌트 분리
src 폴더에 components 폴더 생성
# p240603\first-my-app\src\App.js
import logo from './logo.svg';
import React from 'react';
import './App.css';
import H1 from './components/H1';
import Form from './components/Form';
import MainCard from './components/MainCard';
import Favorites from './components/Favorites';
const jsonLocalStorage = {
setItem: (key, value) => {
localStorage.setItem(key, JSON.stringify(value));
},
getItem: (key) => {
return JSON.parse(localStorage.getItem(key));
},
}
/* component : 상태 끌어올리기(lifting state up) */
const App = () => {
const foodOne = "img/food-one.jpg";
const foodTwo = "img/food-two.jpg";
const foodTree = "img/food-three.jpg";
// 보여지는 이미지 상태값
const [favorites, setFavorites] = React.useState(() => {
// 초기값 빈 배열로 설정
return jsonLocalStorage.getItem('favorites') || [];
});
// 페이지수 상태값
const [counter, setCounter] = React.useState(() => {
return jsonLocalStorage.getItem('counter');
}
);
// 좋아요 버튼 상태값
const [heartCounter, setHeartCounter] = React.useState(0);
function updateCounter() {
setCounter((pre) => {
const nextCounter = pre + 1;
jsonLocalStorage.setItem('counter', nextCounter);
return nextCounter;
});
}
function handlerHeartClick() {
setHeartCounter(heartCounter + 1);
setFavorites((pre) => {
const nextFavorites = [...pre, foodTree];
jsonLocalStorage.setItem('favorites', nextFavorites);
return nextFavorites;
});
}
return (
<div>
<H1>{counter}</H1>
<Form updateCounter={updateCounter} />
<MainCard
img="img/food-one.jpg"
handlerHeartClick={handlerHeartClick}
heartCounter={heartCounter}
/>
<Favorites favorites={favorites} />
</div>
);
}
export default App;
# p240603\first-my-app\src\components\Favorites.js
import FoodItem from "./FoodItem";
/* component */
const Favorites = ({ favorites }) => {
return (
<ul className="favorites">
{favorites.map((food, index) => (<FoodItem img={food} key={index} />))}
</ul>
);
}
export default Favorites;
# p240603\first-my-app\src\components\FoodItem.js
/* component */
const FoodItem = ({ img }) => {
return (
<li>
<img
src={img}
alt="음식"
style={{ width: '150px', height: '100px', backgroundSize: 'contain' }}
/>
</li>
);
}
export default FoodItem;
# p240603\first-my-app\src\components\Form.js
import React from 'react';
/* component */
const Form = ({ updateCounter }) => {
const [value, setValue] = React.useState('');
const [errorMsg, setErrorMsg] = React.useState('');
const hangul = (text) => /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(text);
function handlerInputChange(data) {
const userValue = data.target.value;
setValue(userValue.toUpperCase());
if (hangul(userValue)) {
setErrorMsg('한글은 입력할 수 없습니다.');
} else {
setErrorMsg('');
}
}
function handlerFormSubmit(event) {
event.preventDefault();
if (value === '') {
setErrorMsg('빈 값은 추가 할 수 없습니다.');
return;
}
updateCounter();
}
return (
<form action="" onSubmit={handlerFormSubmit}>
<input
type="text"
name="name"
placeholder="상품명을 입력하세요"
onChange={handlerInputChange}
value={value}
/>
<button type="submit">추가</button>
<p style={{ color: '#f00' }}>{errorMsg}</p>
</form>
);
}
export default Form;
# p240603\first-my-app\src\components\H1.js
/* component */
const H1 = (props) => {
return <h1>상품 {props.children} 페이지</h1>
}
export default H1;
# p240603\first-my-app\src\components\MainCard.js
/* component */
const MainCard = ({ img, handlerHeartClick, heartCounter }) => {
return (
<div className="main-card">
<img
src={img}
alt="올리브 오일"
width="400"
/>
<button onClick={handlerHeartClick}>
🤍{heartCounter > 0 && heartCounter}
</button>
</div>
);
}
export default MainCard;