styled-components의 장점
npm install styled-components
로 설치App.js
import styled from 'styled-components';
Detail.js
// 스타일이 입혀진 button이 된 것이다.
let YellowBtn = styled.button`
background: yellow;
color: black;
padding: 10px;
`
function Detail(props) {
// 이 때 id로는 string 형태가 들어온다.
let {id} = useParams();
let detail = props.shoes.find(x => x.id === Number(id));
return (
<div className="container">
<YellowBtn>버튼</YellowBtn>
<style>
이라는 태그로 만들어져서 HTML 파일에 들어가게 된다.let YellowBtn = styled.button`
background: ${props => props.bg};
...
<YellowBtn bg="blue">버튼</YellowBtn>
styled 컴포넌트에서는 프로그래밍이 가능해진다.
// 스타일이 입혀진 button이 된 것이다.
let YellowBtn = styled.button`
background: ${props => props.bg};
color: ${props => props.bg == 'blue' ? 'white' : 'black'};
padding: 10px;
`
...
// 복사해서 커스터마이징이 가능하다.
let NewBtm = styled.button(YellowBtn)`
// 커스터마이징 가능
`
옛날 방식(component)
// 옛날 방식
class Detail2 extends React.Component {
componentDidMount() {
// mount 될 때 해당 코드가 실행된다.
}
componentDidUpdate() {
// update 될 때 해당 코드가 실행된다.
}
componentWillUnmount() {
// unmount 될 때 해당 코드가 실행된다.
}
}
요즘 방식(function)
function Detail(props) {
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
console.log('hi');
})
...
useEffect를 사용하는 이유
function Detail(props) {
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
})
for (let i = 0; i < 50000; i++) {
console.log(1);
}
위와 같이 할 경우 for문이 오래 걸려 HTML을 늦게 보여줄 수 있다. 밑과 같이 고쳐주면 좋다.
function Detail(props) {
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
for (let i = 0; i < 50000; i++) {
console.log(1);
}
})
function Detail(props) {
let [discountDisplay, setDiscountDisplay] = useState(true);
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
setTimeout(() => {setDiscountDisplay(false)}, 2000);
})
...
return (
<div className="container">
{discountDisplay === true ? <Discount></Discount> : null}
<div className="row">
...
function Discount() {
return (
<div className="alert alert-warning">
2초 이내 구매 시 할인
</div>
);
}
dependency
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
setTimeout(() => {setAlert(false)}, 2000)
console.log(1);
})
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
setTimeout(() => {setAlert(false)}, 2000)
console.log(1);
}, [])
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
setTimeout(() => {setAlert(false)}, 2000)
console.log(1);
}, [count])
return
useEffect(() => {
// mount, update될 때 여기의 코드가 실행된다.
// 이렇게 작성하여도, setTimeout 함수는 실행된다. 함수를 실행하는 ()가 붙어 있기 때문이다.
let timer = setTimeout(() => {setAlert(false)}, 2000)
return () => {
clearTimeout(timer);
}
})
정리
useEffect(() => {})
useEffect(() => {}, [])
useEffect(() => {
return () => {
}
}, [])
서버에 데이터 요청 시
ajax
npm install axios
입력하여 라이브러리 설치import axios from 'axios'
<Button variant="success" onClick={() => {
// ajax GET 요청
// axios.get('url')
axios.get('https://codingapple1.github.io/shop/data2.json')
// 요청결과는 axios.get('url').then()
// data가 ajax GET을 통해 받아온 데이터이다.
.then((result) => {
// console.log(result);
console.log(result.data);
})
}}>Ajax</Button>
<Button variant="success" onClick={() => {
// ajax GET 요청
// axios.get('url')
axios.get('https://codingapple1.github.io/shop/data2.json')
// 요청결과는 axios.get('url').then()
// data가 ajax GET을 통해 받아온 데이터이다.
.then((result) => {
// console.log(result);
console.log(result.data);
})
// ajax 요청 시 실패할 경우 특정 코드를 실행하고 싶다면 catch 사용
// 즉 예외 처리
.catch(() => {
console.log('실패');
})
}}>Ajax</Button>
<Button variant="success" onClick={() => {
axios.get('https://codingapple1.github.io/shop/data2.json')
.then((result) => {
let newShoes = [...shoes];
// let newShoes = [...shoes, ...result.data];
result.data.forEach((element) => {
newShoes.push(element);
})
setShoes(newShoes);
});
}}>Ajax</Button>
* 배열들을 합칠 때에도 spread operator를 사용할 수 있다.
POST
axios.post('/url을 적으면 된다.', {name : 'kim'})
// 데이터 요청을 여러 군데에 하고 싶을 때
Promise.all([axios.get('/url1'), axios.get('/url2')])
.then((result) => {
})
// fetch
fetch('url')
.then(result => result.json())
.then((result) => {
console.log(result);
})
<Nav variant="tabs" defaultActiveKey="link0">
<Nav.Item>
<Nav.Link eventKey="link0">버튼0</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link1">버튼1</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link2">버튼2</Nav.Link>
</Nav.Item>
</Nav>
{ tab === 0 ? <div>내용0</div> : null}
{ tab === 1 ? <div>내용1</div> : null}
{ tab === 2 ? <div>내용2</div> : null}
function TabContent(props) {
if (props.tab === 0) {
return <div>내용0</div>
}
if (props.tab === 1) {
return <div>내용1</div>
}
if (props.tab === 2) {
return <div>내용2</div>
}
}
...
<Nav variant="tabs" defaultActiveKey="link0">
<Nav.Item>
<Nav.Link eventKey="link0" onClick={() => setTab(0)}>버튼0</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link1" onClick={() => setTab(1)}>버튼1</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link2" onClick={() => setTab(2)}>버튼2</Nav.Link>
</Nav.Item>
</Nav>
{/* 삼항연산자를 여러 개 쓰면 비효율적이다. */}
{/* { tab === 0 ? <div>내용0</div> : null}
{ tab === 1 ? <div>내용1</div> : null}
{ tab === 2 ? <div>내용2</div> : null} */}
<TabContent tab={tab}></TabContent>
</div>
);
}
function TabContent(props) {
if (props.tab === 0) {
return <div>내용0</div>
}
if (props.tab === 1) {
return <div>내용1</div>
}
if (props.tab === 2) {
return <div>내용2</div>
}
}
...
function TabContent({tab}) {
// function TabContent({prop1, prop2 ...})
if (tab === 0) {
return <div>내용0</div>
}
if (tab === 1) {
return <div>내용1</div>
}
if (tab === 2) {
return <div>내용2</div>
}
}
// 이렇게 array를 이용하는 것도 가능하다.
function TabContent({tab}) {
return [<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]
}
.start {
opacity: 0;
}
.end {
opacity: 1;
transition: opacity 0.5s;
}
<Nav variant="tabs" defaultActiveKey="link0">
<Nav.Item>
<Nav.Link eventKey="link0" onClick={() => setTab(0)}>버튼0</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link1" onClick={() => setTab(1)}>버튼1</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="link2" onClick={() => setTab(2)}>버튼2</Nav.Link>
</Nav.Item>
</Nav>
...
function TabContent({tab}) {
return (
<div className="start">
{[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]}
</div>
)
}
function TabContent({tab}) {
let [fade, setFade] = useState('');
useEffect(() => {
setFade('end');
}, [tab])
return (
<div className={'start ' + fade}>
{/* <div className={`start ${fade}`} */}
{[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]}
</div>
)
}
useEffect(() => {
// setFade('');
setFade('end');
return () => {
setFade('');
}
}, [tab])
function TabContent({tab}) {
let [fade, setFade] = useState('');
useEffect(() => {
let timer = setTimeout(() => { setFade('end')}, 10);
return () => {
clearTimeout(timer);
setFade('');
}
}, [tab])
return (
<div className={'start ' + fade}>
{/* <div className={`start ${fade}`} */}
{[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][tab]}
</div>
)
}
Single Page Application의 단점
이렇게 여러 번 state를 쓰는 것이 귀찮다면
Context API
function App() {
let [shoes, setShoes] = useState(data);
let [userClicks, setUserClicks] = useState(1);
let [loadingDisplay, setLoadingDisplay] = useState(false);
let [stocks, setStocks] = useState([10, 11, 12]);
App.js
...
let context1 = createContext();
function App() {
...
App.js
2. <Context>
로 원하는 컴포넌트 감싸기
App.js
3. 공유하고 싶은 state를 value 속성에 담는다.
...
<Route path="/detail/:id" element={
<context1.Provider value={{ stocks }}>
<Detail shoes={shoes}></Detail>
</context1.Provider>
}></Route>
...
Detail.js
4. 쓰고 싶은 컴포넌트에서 Context를 import 한다.
import { Context1 } from './../App.js'
App.js
5. 해당 Context를 export(1번에서 해줘도 된다.)
export let context1 = createContext();
Detail.js
6. useContext(Context)로 공유된 state를 사용한다.
function Detail(props) {
// let stocks = useContext(Context1);
let {stocks} = useContext(Context1);
Detail.js
파일에서 Detail 컴포넌트 뿐만 아니라, 그 자식인 TabContent 컴포넌트에서도 stocks가 사용 가능해진다.function TabContent(props) {
let {stocks} = useContext(Context1);
let [fade, setFade] = useState('');
useEffect(() => {
let timer = setTimeout(() => { setFade('end')}, 10);
return () => {
clearTimeout(timer);
setFade('');
}
}, [props.tab])
return (
<div className={'start ' + fade}>
{/* <div className={`start ${fade}`} */}
{stocks}
{[<div>내용0</div>, <div>내용1</div>, <div>내용2</div>][props.tab]}
</div>
)
}
Context API의 단점