일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 비트 연산자
- 타입스크립트
- Redux
- 컴포넌트
- 원티드
- v9
- TypeScript
- react localStorage
- CORS
- 파이어베이스
- 자바스크립트
- 리액트
- 프론트엔드
- JavaScript
- 프리온보딩
- til
- state
- 프로그래머스
- localstorage
- Component
- firebase
- Frontend
- es6
- JS
- 브라우저
- react
- axios
- 알고리즘
- Reducer
- array
Archives
- Today
- Total
도리쓰에러쓰
[React] Component가 많을 땐 Context API 사용하기 본문
저번 게시물에 이어서 작성하겠습니다. (코드 참고)
1. Context API 사용하기
📌 Context API 사용하는 이유
: props에 전달하지 않고도 하위컴포넌트들이 props 없이도 부모의 값을 사용 가능
저는 이전에 만들었던 inventory state를 가지고 Context API를 사용해보겠습니다.
let [inventory, setInventory] = useState([10, 11, 12]);
1️⃣ React.createContext()로 범위 생성
- 같은 변수값을 공유할 범위 생성
let inventoryContext = React.createContext();
2️⃣ 값 공유를 원하는 HTML들을 <범위변수명.Provider>로 감싸기
💡 value={공유하고 싶은 데이터}
<inventoryContext.Provider value={inventory}>
<div className='row'>
{
products.map((a, i) => {
return <Card products={a} num={i} key={i}/>
})
}
</div>
</inventoryContext.Provider>
3️⃣ useContext(범위변수명)로 공유된 값 사용하기
let inventory = useContext(inventoryContext);
<p>재고 : { inventory[0] }</p>
💡 간단한 데이터 전송은 props를 사용하면 좋고, Component 안에 Component가 있는 경우엔 Context API를 사용하는게 좋을 것 같습니다.
✨ 다른 파일에 값을 공유하고 싶다면?
1️⃣ 범위 생성했던 변수를 export 합니다.
export let inventoryContext = React.createContext();
2️⃣ 마찬가지로 값 공유를 원하는 HTML들을 <범위변수명.Provider>로 감쌉니다.
<inventoryContext.Provider value={inventory}>
<Detail products={ products } setInventory={ setInventory } />
</inventoryContext.Provider>
3️⃣ 범위 생성했던 변수를 다른 파일로 import 합니다.
import { inventoryContext } from './App.js';
2. 전체 코드
App.js
/* eslint-disable */
import React, { useState, useContext } from 'react'
import { Navbar, Container, Nav, NavDropdown, Button } from 'react-bootstrap';
import './App.css';
import data from './data.js';
import Detail from './Detail.js';
import axios from 'axios';
import { Link, Route, Switch } from 'react-router-dom';
export let inventoryContext = React.createContext();
function App() {
let [products, setProducts] = useState(data);
let [inventory, setInventory] = useState([10, 11, 12]);
return (
<div className="App">
<Navbar bg="light" expand="lg">
<Container>
<Navbar.Brand href="#home">Saint Laurent</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
<Nav.Link as={Link} to="/">Home</Nav.Link>
<Nav.Link as={Link} to="/detail">Detail</Nav.Link>
<NavDropdown title="Dropdown" id="basic-nav-dropdown">
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2">Another action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item>
</NavDropdown>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<Switch>
<Route exact path="/">
<div className='Jumbotron'>
<h1>20% Season Off</h1>
<p>
This is a simple hero unit, a simple jumbotron-style component for calling
extra attention to featured content or information.
</p>
<p>
<Button variant="primary">Learn more</Button>
</p>
</div>
<div className='container'>
<inventoryContext.Provider value={inventory}>
<div className='row'>
{
products.map((a, i) => {
return <Card products={a} num={i} key={i}/>
})
}
</div>
</inventoryContext.Provider>
<button className='btn btn-primary' onClick={()=>{
axios.get('https://codingapple1.github.io/shop/data2.json')
.then((result)=>{
setProducts([...products, ...result.data])
})
.catch(()=>{
console.log('fail');
})
}}>더보기</button>
</div>
</Route>
<Route path="/detail/:id">
<inventoryContext.Provider value={inventory}>
<Detail products={ products } inventory={ inventory } setInventory={ setInventory } />
</inventoryContext.Provider>
</Route>
<Route path="/:id">
<div>아무말</div>
</Route>
</Switch>
</div>
);
}
function Card(props) {
let inventory = useContext(inventoryContext);
return(
<div className='col-md-4'>
<img className="img" src={ 'images/img'+ (props.num + 1) +'.jpg' } />
<h4>{ props.products.title }</h4>
<p>{ props.products.content }</p>
<p>{ props.products.price }</p>
<p>재고 : { inventory[props.num] }</p>
</div>
)
}
export default App;
Detail.js
import React, { useContext, useEffect, useState } from 'react';
import { useHistory, useParams } from 'react-router-dom';
import styled from 'styled-components';
import { inventoryContext } from './App.js';
import './Detail.scss';
let Box = styled.div`
padding : 20px;
`;
let Title = styled.h4`
font-size : 25px;
color : ${ props => props.color }
`;
function Detail(props) {
let { id } = useParams();
let history = useHistory();
let findProduct = props.products.find(function(product) {
return product.id = id;
});
let [alert, setAlert] = useState(true);
let [inputData, setInputData] = useState('');
useEffect(()=>{
let timer = setTimeout(() => { setAlert(false) }, 2000);
return ()=>{ clearTimeout(timer) }
}, []);
function inventoryOut() {
let id = findProduct.id;
let copyArr = [...props.inventory];
copyArr[id] = copyArr[id] - 1;
props.setInventory(copyArr);
}
let inventory = useContext(inventoryContext);
return(
<div className='container'>
<Box>
<Title className='red'>상세페이지</Title>
</Box>
<input onChange={ (e)=>{ setInputData(e.target.value) } }/>
{
alert === true
? (<div className='my-alert-red'>
<p>재고가 얼마 남지 않았습니다!</p>
</div>)
: null
}
<div className='row'>
<div className='col-md-6'>
<img className='img' src={ process.env.PUBLIC_URL + '/images/img'+ (Number(findProduct.id) + 1)+'.jpg' } />
</div>
<div className='col-md-6 mt-4'>
<h4 className='pt-5'>{ findProduct.title }</h4>
<p>{ findProduct.content }</p>
<p>{ findProduct.price }</p>
<Info id={ findProduct.id } inventory={ props.inventory }> </Info>
<button className='btn btn-danger' onClick={ () => { inventoryOut() } }>주문하기</button>
<br />
<br />
<button className='btn btn-danger' onClick={ () => {
history.goBack();
}}>뒤로가기</button>
</div>
</div>
</div>
)
}
function Info(props) {
return(
<p> 재고 : { props.inventory[props.id] }</p>
)
}
export default Detail;
* 이외의 코드는 이전 게시물에 작성된 코드와 일치합니다.
'코딩애플 (React) > 기초수업(코딩애플) - 3' 카테고리의 다른 글
[React] Redux3 :: state와 reducer가 더 필요하다면? (0) | 2022.01.31 |
---|---|
[React] Redux2 :: reducer / dispatch로 데이터 수정하기 (0) | 2022.01.26 |
[React] Redux1 :: props 대신 사용하기 (0) | 2022.01.26 |
[React] Tab 만들기와 리액트에서의 등장 애니메이션 (0) | 2022.01.24 |
[React] 리액트 사이트 build & Github Pages로 배포하기 (0) | 2022.01.23 |
Comments