State (์ํ)
์ปดํฌ๋ํธ๊ฐ ๊ด๋ฆฌํ๋ ๋ก์ปฌ(๋ด๋ถ) ๋ฐ์ดํฐ
React ์ปดํฌ๋ํธ์ ์ํ(State)๋ ์ปดํฌ๋ํธ๊ฐ ๊ด๋ฆฌํ๋ ๋ก์ปฌ ๋ฐ์ดํฐ์
๋๋ค. ์ํ๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ํ์ํ ์ ์์ผ๋ฉฐ, ์ํ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค React๋ ์๋์ผ๋ก ํ๋ฉด์ ๋ค์ ๋ ๋๋งํฉ๋๋ค.
State ์ ํน์ง
1.
์ํ ์ด๊ธฐํ
: ์ปดํฌ๋ํธ๊ฐ ์์ฑ๋ ๋ useState ํ
์ด๋ ํด๋์ค ์ปดํฌ๋ํธ์ constructor ๋ฉ์๋์์ ์ด๊ธฐ ์ํ๋ฅผ ์ค์ ํฉ๋๋ค.
2.
์ํ ์
๋ฐ์ดํธ
: setCount๋ this.setState๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. ์ด๋ ์ด์ ์ํ๋ฅผ ์ฐธ์กฐํ์ฌ ๋ณ๊ฒฝ์ ์งํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
3.
์ปดํฌ๋ํธ๋ณ๋ก ๊ณ ์ ํ ์ํ
: ๊ฐ๊ฐ์ ์ธ์คํด์ค๋ ์์ฒด ์ํ๋ฅผ ์ ์งํ๋ฏ๋ก, ๋์ผํ ์ปดํฌ๋ํธ์ ์ฌ๋ฌ ์ธ์คํด์ค ๊ฐ์๋ ๊ฐ๊ฐ ๋
๋ฆฝ์ ์ธ ์ํ๊ฐ ์กด์ฌํฉ๋๋ค.
์ค์ต ์ฝ๋
โ์ํ ์์ธ UI ๋ง๋ค๊ธฐ - stateโ
โ์ํ ์์ธ UI ๋ง๋ค๊ธฐ - stateโ ์์๋ 1~3๋จ๊ณ๋ก ๋๋์ด ์ค์ตํฉ๋๋ค.
1๋จ๊ณ - JSX ๋ฌธ๋ฒ๋ง์ ์ฌ์ฉํ์ฌ ProductDetail.jsx ์ปดํฌ๋ํธ๋ฅผ ์ ์ ์ปจํ
์ธ ๋ก ๋์์ธํฉ๋๋ค.
2๋จ๊ณ - JavaScript ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ, ๋์ ์ผ๋ก ์ํ ์์ธ ์ ๋ณด๋ฅผ ๋๋๋ง ํฉ๋๋ค.
3๋จ๊ณ - quantity (์๋) ์ ์ํ(state) ๋ก ์ ์ํ์ฌ,
,
๋ฒํผ์ ๋๋ฌ ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ฅผ ํ๊ณ , ์ํ๋ณํ์ ๋ฐ๋ผ ๋ฆฌ๋๋๋งํ๋ ๊ณผ์ ์ ํ์ธํฉ๋๋ค.
์์ ํ ํ์ผ
โข
componets/ProductDetail.jsx
โข
App.js
โข
App.css
1๋จ๊ณ
JSX ๋ฌธ๋ฒ๋ง์ ์ฌ์ฉํ์ฌ ProductDetail.jsx ์ปดํฌ๋ํธ๋ฅผ ์ ์ ์ปจํ
์ธ ๋ก ๋์์ธํฉ๋๋ค
โข
componets/ProductDetail.jsx
โข
App.js
โข
App.css
์ปดํฌ๋ํธ ๊ตฌ์กฐ
โข
App
โฆ
ProductDetail
App, ProductDetail ์ปดํฌ๋ํธ
componets/ProductDetail.jsx
import React from 'react'
const ProductDetail = () => {
return (
<div className='product-detail'>
<div className="item img">
<img src="https://i.imgur.com/1vpSkbW.png" alt="์ํ๋ช
" />
</div>
<div className="item info">
<div className="title">
<h1>์ํ๋ช
</h1>
</div>
<p>
<span className='txt-pt'>INFO</span><br />
-ํธ์ํ ์ฐฉ์ฉ์ด ๊ฐ๋ฅํ ํด๋ผ ๋์์ธ <br />
-์ฒดํ ์ปค๋ฒ๊ฐ ๊ฐ๋ฅํ ๋ฒ ์ด์งํ ์ค๋ฃจ์ฃ <br />
</p>
<p>
<span className="txt-pt">Color & Size</span> <br />
Black, Navy, Red <br />
85, 90, 95, 100, 110 <br />
- ์ด๊นจ 53, ๊ฐ์ด 59, ์ํ 23, ์๋งค 62, ์ด์ฅ 68 <br />
(์ธก์ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ 1~3cm ์ค์ฐจ๊ฐ ์์ ์ ์์ต๋๋ค) <br />
</p>
<span className='line-lg'></span>
<div className="text-group">
<div className="item">
<span className='txt-pt'>ํ๋งค๊ฐ</span>
</div>
<div className="item">
<span className='txt-pt'>42,000 ์</span>
</div>
</div>
<div className="text-group">
<div className="item">
<span>๋ฐฐ์ก๋น</span>
</div>
<div className="item">
<span>3,000</span> ์
</div>
</div>
<span className="line-lg"></span>
<div className="text-group">
<div className="item">
<span>Color</span>
</div>
<div className="item">
<select name="color" id="color">
<option value="Black">Black</option>
<option value="Navy">Navy</option>
<option value="Red">Red</option>
</select>
</div>
</div>
<div className="text-group">
<div className="item">
<span>Size</span>
</div>
<div className="item">
<select name="color" id="color">
<option value="85">85</option>
<option value="90">90</option>
<option value="95">95</option>
<option value="100">100</option>
<option value="110">110</option>
</select>
</div>
</div>
<div className="text-group">
<div className="item">
<span>์๋</span>
</div>
<div className="item flex">
<input type="text" className='quantity' min={1} max={100} value={1} />
<button className='btn btn-xs'>+</button>
<button className='btn btn-xs'>-</button>
</div>
</div>
<span className="line-lg"></span>
<div className="text-group">
<div className="item">
<span className='txt-pt'>์ต์ข
๊ฐ๊ฒฉ</span>
</div>
<div className="item">
<span className='txt-pt'>42,000</span>
</div>
</div>
<div className="text-group flex gap-1">
<div className="item">
<button className="btn btn-lg">๊ตฌ๋งคํ๊ธฐ</button>
</div>
<div className="item flex">
<button className="btn btn-lg btn-outline">์ฅ๋ฐ๊ตฌ๋</button>
<button className="btn btn-lg btn-outline">๊ด์ฌ์ํ</button>
</div>
</div>
</div>
</div>
)
}
export default ProductDetail
JavaScript
๋ณต์ฌ
App.js
import logo from './logo.svg';
import './App.css';
import ProductDetail from './components/ProductDetail';
function App() {
return (
<div>
<ProductDetail />
</div>
);
}
export default App;
JavaScript
๋ณต์ฌ
App.css
.txt-pt {
color: salmon;
font-weight: bold;
}
.line-lg {
display: block;
border-bottom: 2px solid lightgray;
}
.product-detail {
display: inline-flex;
justify-content: center;
column-gap: 100px;
padding: 10px;
/* border: 1px solid salmon; */
}
.product-detail .item {
width: 400px;
}
.product-detail .info {
border-top: 2px solid black;
border-bottom: 2px solid black;
}
.quantity {
width: 40px;
font-size: 16px;
line-height: 20px;
height: 20px;
text-align: center;
appearance: none;
}
/* ๊ณตํต */
.text-group {
display: flex;
padding: 10px 0;
}
img { width: 100%; }
select {
width: 100%;
font-size: 16px;
line-height: 40px;
height: 40px;
padding-left: 15px;
padding-right: 15px;
color: #222;
color: inherit;
cursor: pointer;
outline: none;
border: 1px solid #777;
background: none;
border-radius: 0;
padding-right: 32px;
}
.flex {
display: flex;
}
.flex.gap-1 {
gap: 10px;
}
.btn {
background-color: royalblue;
color: white;
font-weight: bold;
outline: none;
border: none;
margin: 0 2px;
padding: 0 10px;
cursor: pointer;
}
.btn:hover {
box-shadow: 2px 2px 2px rgba(0,0,0,0.5);
}
.btn:active {
box-shadow: none;
}
.btn.btn-lg {
width: 100%;
min-height: 40px;
}
.btn.btn-outline {
border: 2px solid gray;
background-color: white;
color: gray;
}
CSS
๋ณต์ฌ
2๋จ๊ณ
JavaScript ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ, ๋์ ์ผ๋ก ์ํ ์์ธ ์ ๋ณด๋ฅผ ๋๋๋ง ํฉ๋๋ค.
โข
componets/ProductDetail.jsx
์ปดํฌ๋ํธ ๊ตฌ์กฐ
โข
App
โฆ
ProductDetail
App, ProductDetail ์ปดํฌ๋ํธ
componets/ProductDetail.jsx
import React, { useState } from 'react'
const ProductDetail = (props) => {
// โ
๊ฐ์ฒด ์ถ๊ฐ
const product = {
productId : 'p000001',
name : '๋ฒ ์ด์ง ํด๋ผ ๋ํธ',
price : 42000,
quantity : 1,
img: 'https://i.imgur.com/1vpSkbW.png',
}
// โ
์ต์ข
๊ฐ๊ฒฉ ๊ณ์ฐ
const totalPrice = product.price * product.quantity
return (
<div className='product-detail'>
<div className="item img">
<img src={product.img} alt={product.name} />
</div>
<div className="item info">
<div className="title">
<h1>{product.name}</h1>
</div>
<p>
<span className='txt-pt'>INFO</span><br />
-ํธ์ํ ์ฐฉ์ฉ์ด ๊ฐ๋ฅํ ํด๋ผ ๋์์ธ <br />
-์ฒดํ ์ปค๋ฒ๊ฐ ๊ฐ๋ฅํ ๋ฒ ์ด์งํ ์ค๋ฃจ์ฃ <br />
</p>
<p>
<span className="txt-pt">Color & Size</span> <br />
Black, Navy, Red <br />
85, 90, 95, 100, 110 <br />
- ์ด๊นจ 53, ๊ฐ์ด 59, ์ํ 23, ์๋งค 62, ์ด์ฅ 68 <br />
(์ธก์ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ 1~3cm ์ค์ฐจ๊ฐ ์์ ์ ์์ต๋๋ค) <br />
</p>
<span className='line-lg'></span>
<div className="text-group">
<div className="item">
<span className='txt-pt'>ํ๋งค๊ฐ</span>
</div>
<div className="item">
<span className='txt-pt'>{product.price.toLocaleString()} ์</span>
</div>
</div>
<div className="text-group">
<div className="item">
<span>๋ฐฐ์ก๋น</span>
</div>
<div className="item">
<span>3,000</span> ์
</div>
</div>
<span className="line-lg"></span>
<div className="text-group">
<div className="item">
<span>Color</span>
</div>
<div className="item">
<select name="color" id="color">
<option value="Black">Black</option>
<option value="Navy">Navy</option>
<option value="Red">Red</option>
</select>
</div>
</div>
<div className="text-group">
<div className="item">
<span>Size</span>
</div>
<div className="item">
<select name="color" id="color">
<option value="85">85</option>
<option value="90">90</option>
<option value="95">95</option>
<option value="100">100</option>
<option value="110">110</option>
</select>
</div>
</div>
<div className="text-group">
<div className="item">
<span>์๋</span>
</div>
<div className="item flex">
<input type="text" className='quantity' value={product.quantity} min={1} max={100} />
<button className='btn btn-xs'>+</button>
<button className='btn btn-xs'>-</button>
</div>
</div>
<span className="line-lg"></span>
<div className="text-group">
<div className="item">
<span className='txt-pt'>์ต์ข
๊ฐ๊ฒฉ</span>
</div>
<div className="item">
<span className='txt-pt'>{totalPrice.toLocaleString()} ์</span>
</div>
</div>
<div className="text-group flex gap-1">
<div className="item">
<button className="btn btn-lg">๊ตฌ๋งคํ๊ธฐ</button>
</div>
<div className="item flex">
<button className="btn btn-lg btn-outline">์ฅ๋ฐ๊ตฌ๋</button>
<button className="btn btn-lg btn-outline">๊ด์ฌ์ํ</button>
</div>
</div>
</div>
</div>
)
}
export default ProductDetail
JavaScript
๋ณต์ฌ
3๋จ๊ณ
quantity (์๋) ์ ์ํ(state) ๋ก ์ ์ํ์ฌ,
,
๋ฒํผ์ ๋๋ฌ ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ฅผ ํ๊ณ , ์ํ๋ณํ์ ๋ฐ๋ผ ๋ฆฌ๋๋๋งํ๋ ๊ณผ์ ์ ํ์ธํฉ๋๋ค.
โข
componets/ProductDetail.jsx
์ปดํฌ๋ํธ ๊ตฌ์กฐ
โข
App
โฆ
ProductDetail
App, ProductDetail ์ปดํฌ๋ํธ
componets/ProductDetail.jsx
import React, { useState } from 'react'
const ProductDetail = (props) => {
// โ
state ์ถ๊ฐ
const [quantity, setQuantity] = useState(1)
// โ
๊ฐ์ฒด ์ถ๊ฐ
const product = {
productId : 'p000001',
name : '๋ฒ ์ด์ง ํด๋ผ ๋ํธ',
price : 42000,
quantity : 1,
img: 'https://i.imgur.com/1vpSkbW.png',
}
// โ
์ต์ข
๊ฐ๊ฒฉ ๊ณ์ฐ
const totalPrice = product.price * quantity
// โ
์ด๋ฒคํธ ์ ์ - ์ฆ๊ฐ
const onIncrease = () => {
console.log(quantity);
setQuantity(quantity + 1)
}
// โ
์ด๋ฒคํธ ์ ์ - ๊ฐ์
const onDecrease = () => {
console.log(quantity);
setQuantity(quantity - 1)
}
return (
<div className='product-detail'>
<div className="item img">
<img src={product.img} alt={product.name} />
</div>
<div className="item info">
<div className="title">
<h1>{product.name}</h1>
</div>
<p>
<span className='txt-pt'>INFO</span><br />
-ํธ์ํ ์ฐฉ์ฉ์ด ๊ฐ๋ฅํ ํด๋ผ ๋์์ธ <br />
-์ฒดํ ์ปค๋ฒ๊ฐ ๊ฐ๋ฅํ ๋ฒ ์ด์งํ ์ค๋ฃจ์ฃ <br />
</p>
<p>
<span className="txt-pt">Color & Size</span> <br />
Black, Navy, Red <br />
85, 90, 95, 100, 110 <br />
- ์ด๊นจ 53, ๊ฐ์ด 59, ์ํ 23, ์๋งค 62, ์ด์ฅ 68 <br />
(์ธก์ ๋ฐฉ๋ฒ์ ๋ฐ๋ผ 1~3cm ์ค์ฐจ๊ฐ ์์ ์ ์์ต๋๋ค) <br />
</p>
<span className='line-lg'></span>
<div className="text-group">
<div className="item">
<span className='txt-pt'>ํ๋งค๊ฐ</span>
</div>
<div className="item">
<span className='txt-pt'>{product.price.toLocaleString()} ์</span>
</div>
</div>
<div className="text-group">
<div className="item">
<span>๋ฐฐ์ก๋น</span>
</div>
<div className="item">
<span>3,000</span> ์
</div>
</div>
<span className="line-lg"></span>
<div className="text-group">
<div className="item">
<span>Color</span>
</div>
<div className="item">
<select name="color" id="color">
<option value="Black">Black</option>
<option value="Navy">Navy</option>
<option value="Red">Red</option>
</select>
</div>
</div>
<div className="text-group">
<div className="item">
<span>Size</span>
</div>
<div className="item">
<select name="color" id="color">
<option value="85">85</option>
<option value="90">90</option>
<option value="95">95</option>
<option value="100">100</option>
<option value="110">110</option>
</select>
</div>
</div>
<div className="text-group">
<div className="item">
<span>์๋</span>
</div>
<div className="item flex">
<input type="text" className='quantity' value={quantity} min={1} max={100} /> {/* value ๋ฅผ state ๋ก ๋ณ๊ฒฝ */}
<button className='btn btn-xs' onClick={ onIncrease }>+</button> {/* ์ด๋ฒคํธ ์ถ๊ฐ */}
<button className='btn btn-xs' onClick={ onDecrease }>-</button> {/* ์ด๋ฒคํธ ์ถ๊ฐ */}
</div>
</div>
<span className="line-lg"></span>
<div className="text-group">
<div className="item">
<span className='txt-pt'>์ต์ข
๊ฐ๊ฒฉ</span>
</div>
<div className="item">
<span className='txt-pt'>{totalPrice.toLocaleString()} ์</span>
</div>
</div>
<div className="text-group flex gap-1">
<div className="item">
<button className="btn btn-lg">๊ตฌ๋งคํ๊ธฐ</button>
</div>
<div className="item flex">
<button className="btn btn-lg btn-outline">์ฅ๋ฐ๊ตฌ๋</button>
<button className="btn btn-lg btn-outline">๊ด์ฌ์ํ</button>
</div>
</div>
</div>
</div>
)
}
export default ProductDetail
JavaScript
๋ณต์ฌ







