리액트 : single page
Single page Application의 단점 : 컴포넌트 간의 state 공유 어려움. 특히, 형제 간의 컴포넌트의 공유
- Lifecycle(생명주기)
class Detail extends React.Component {
componentDidMount() {
// Detail 컴포넌트가 로드 되고나서 실행할 코드
}
componentDidUpdate() {
// Detail 컴포넌트가 업데이트 되고나서 실행할 코드
}
componentWillUnmount() {
// Detail 컴포넌트가 삭제 되기 전에 실행할 코드
}
}
컴포넌트는
1) 생성이 될 수도 있고(mount)
2) 재렌더링이 될 수도 있고(update)
3) 삭제가 될 수도 있다(unmout)
- useEffect 안에 적은 코드는 return 안의 html렌더링 이후에 동작한다
* useEffect 밖에 적은 코드는 위에서부터 차례대로 실행(렌더링이 나중에 됨)
# html 렌더링이 빠른 사이트를 원하면 시간이 걸리는 코드는 useEffect() 안에
# useEffect안에 적는 코드들
1) 어려운 연산(시간이 걸리는 연산)
2) 서버에서 데이터를 가져오는 작업
3) 타이머 등
- useEffect(()=>{실행할 코드}) : mount,update가 될 때마다 실행
- useEffect(()=>{실행할 코드}, []) : mount되었을 때 1번만 실행
- useEffect(()=>{실행할 코드}, [변수]) : 변수가 변할 때만 실행(update시 실행 안됨)
- useEffect(()=>{
실행할 코드;
return()=>{
실행문보다 먼저 실행할 구문 -> 연속적으로 해야할 것이 있는 경우
}
}, [변수])
App.js
Detail.js로 넘겨준다.
function TabContent({tab, clothes}) {
let [fade, setFade] = useState('');
useEffect(()=>{
setTimeout(()=>{setFade('end')}, 300)
return() => {
setFade('')
}
}, [tab])
return (
<div className={`start ${fade}`}>
{ [<div>{clothes.title}</div>, <div>내용1</div>, <div>내용2</div>] [tab] }
</div>
)
}
공동으로 사용할 수 있는 방법
Context Api 문법
( 잘 사용하지 않음 → 성능 이슈 때문 )
a. 설치 안해도 됨
b. App.js에 import, export 넣어준다.
let [stock, setStock] = useState([10,11,12]);
<Route path='/detail/:id' element={
<Context1.Provider value={{stock, clothes}}>
<Detail clothes={clothes} />
</Context1.Provider>
}/>
c. 사용하고자 하는 곳에서 임포트 해준다 → Detail.js
Redux 외부 라이브러리 사용
설치 : npm i @reduxjs/toolkit@1.8.1 react-redux
⇒ 장바구니
App.js
Cart 컴포넌트 사용 → Cart.js 생성
import { Table } from 'react-bootstrap';
function Cart() {
return (
<>
<Table striped bordered hover>
<thead>
<tr>
<th>#</th>
<th>상품명</th>
<th>수량</th>
<th>변경하기</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>상품</td>
<td>1</td>
<td>변경</td>
</tr>
</tbody>
</Table>
</>
)
}
export default Cart;
설정 → index.js
import { Provider } from 'react-redux';
import store from './store';
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
src에 store.js 생성 → 컴포넌트가 아니라 저장 공간임
사용할 내용?을 등록해주는
import { configureStore, createSlice } from "@reduxjs/toolkit";
let user = createSlice({
name : 'user',
initialState : 'Hong'
})
export default configureStore({
reducer:{
user : user.reducer
}
})
다시 Cart.js
function Cart() {
let state = useSelector((state) => {return state})
console.log(state);
return (
⇒ 위 두 줄을 어디에 넣어도 사용이 가능하다 !
stock에 내용을 추가
import { configureStore, createSlice } from "@reduxjs/toolkit";
let user = createSlice({
name : 'user',
initialState : 'Hong'
})
let stock = createSlice({
name : 'stock',
initialState : [10, 11, 12]
})
let cartItem = createSlice({
name : 'cartItem',
initialState : [{id:0, name:"vest", count:2}, {id:2, name:"jacket", count:1 }]
})
export default configureStore({
reducer:{
user : user.reducer,
stock : stock.reducer
}
})
Cart.js
let cartItem = useSelector((state) => {return state.cartItem})
console.log(cartItem);
return (
<>
<Table striped bordered hover>
<thead>
<tr>
<th>번호</th>
<th>상품명</th>
<th>수량</th>
<th>변경하기</th>
</tr>
</thead>
<tbody>
<tr>
<td>{cartItem[0].id}</td>
<td>{cartItem[0].name}</td>
<td>{cartItem[0].count}</td>
<td>변경</td>
</tr>
<tr>
<td>{cartItem[1].id}</td>
<td>{cartItem[1].name}</td>
<td>{cartItem[1].count}</td>
<td>변경</td>
</tr>
</tbody>
</Table>
</>
)
}
export default Cart;
map을 이용한다.
{
cartItem.map((a)=> {
return (
<tr>
<td>{a.id}</td>
<td>{a.name}</td>
<td>{a.count}</td>
<td>변경</td>
</tr>
)
})
}
return 생략 가능
return (
<>
<Table striped bordered hover>
<thead>
<tr>
<th>번호</th>
<th>상품명</th>
<th>수량</th>
<th>변경하기</th>
</tr>
</thead>
<tbody>
{
cartItem.map( a => {
return (
<tr>
<td>{a.id}</td>
<td>{a.name}</td>
<td>{a.count}</td>
<td>변경</td>
</tr>
)
})
}
</tbody>
</Table>
</>
)
}
export default Cart;
Redux의 state를 변경하고 싶으면,
1. state함수 만들기
store.js
let member = createSlice({
name : 'member',
initialState : 'Kim',
reducers : {
changeName(state) {
return 'jiwon ' + state
}
}
})
2. export하기
export let {changeName} = member.actions
export default configureStore({
reducer:{
user : user.reducer,
stock : stock.reducer,
cartItem : cartItem.reducer,
member : member.reducer
}
3. 사용하는 곳에서 import, dispatch()로 감싸주어야 한다.
Cart.js
let dispatch = useDispatch()
let member = useSelector(state=>state.member)
return (
<>
{member}의 장바구니
<Table striped bordered hover>
<thead>
<tr>
<th>번호</th>
<th>상품명</th>
<th>수량</th>
<th>변경하기</th>
</tr>
</thead>
<tbody>
{
cartItem.map( a => {
return (
<tr>
<td>{a.id}</td>
<td>{a.name}</td>
<td>{a.count}</td>
<td>
<button onClick={()=>{
dispatch(changeName())
}}> 버튼
</button>
</td>
</tr>
)
})
}
</tbody>
</Table>
</>
)
}
export default Cart;
해당 변수에 해당하는 값을 증가시키기 위해 num이라는 변수를 넣어주고,
num.payload 적어준다.
changeAge(state, num) {
state.age += num.payload
}
나이가 5씩 증가한다.
store.js에 내용이 너무 많으면 따로 분리해도 된다.
폴더와 파일을 생성하고 내용을 옮겨준다.
import { configureStore, createSlice } from "@reduxjs/toolkit";
let user2 = createSlice({
name : 'member',
initialState : {name:'Kim', age:20},
reducers : {
changeObj(state) {
state.name = 'Park'
},
changeAge(state, num) {
state.age += num.payload
}
}
})
export let {changeObj, changeAge} = user2.actions
export default user2;
기존 store.js에 분리한 코드들을 사용할 수 있도록 import해준다.
import user2 from './store/userSlice';
Cart.js에서도 경로를 맞춰서 import해준다.
import { changeObj, changeAge } from './../store/userSlice'
장바구니에 상품 추가하기
App.js에서 해당 상품의 이미지를 클릭하면 제품 상세보기 페이지로 가도록 링크 걸어주기
function PListImg(props) {
let navigate = useNavigate(); // 페이지의 이동을 도와주는 함수
return (
<>
<Col md={4}>
<Nav.Link onClick={()=>{ navigate(`/detail/${props.i-1}`) }}>
<img src={`${process.env.PUBLIC_URL}/img/clothes${props.i}.png`} width="80%"/>
</Nav.Link>
<h4>{props.clothes.title}</h4>
<p>{props.clothes.price}</p>
</Col>
</>
)
}
export default App;
store.js 에서 버튼을 누르면, 장바구니에 추가되도록한다.
addItem(state, action) {
state.push({id:0, name:"vest", count:1})
}
임의로 값을 넣어주고, 잘 들어가는지 확인한다.
현재 사용자가 보고 있는 상세페이지에 있는 상품이 들어가도록 해야 한다.
addItem(state, action) {
state.push(action.payload)
}
Detail.js
<Button variant="secondary" onClick={()=>{
dispatch(addItem({id: findId.id, name:findId.title, count:1}))
}}
>주문하기</Button>
'React' 카테고리의 다른 글
[React] TODOLIST (0) | 2024.03.22 |
---|---|
[React] 로컬 스토리지 (0) | 2024.03.22 |
[React] axios (0) | 2024.03.22 |
[React] 리액트 부트스트랩 적용 (0) | 2024.03.21 |
[React] 간단한 맛집 추천 블로그 - 2 (0) | 2024.03.21 |