✍️ React 강의를 듣고 코드를 작성하면서 새로 알게된 점, 메모한 내용들을 남겨보자.
bootstrap을 통해 간편하게 navbar와 container를 가져와서 사용해 보았다.
사용과정 ▼
1) npm install 설치
2) css 코드 넣기 (js 혹은 html에 넣는 방식으로 가능하다.)
3) import 해오기 (대문자로 시작하는 컴포넌트명을 전부 import 한다.)
4) 사용법을 참고하여 원하는 코드를 가져와서 사용
import { Navbar, Container, Nav, Row } from 'react-bootstrap';
import mainImg from './img/main.jpg';
style={{ backgroundImage: 'url(' + mainImg + ')' }}
import
해오면서 변수명 지정하기// css
.main-bg {
height: 300px;
background-image: url('./img/main.jpg');
background-size: cover;
background-position: center;
}
<img src='https://kseul.github.io/imgs/img.jpg' alt='이미지' />
/이미지경로
로 해주면 된다.<img arc="/logo.png" width="80">
import
를 따로 해주지 않아도 되어서 편하지만 권장되는 방식은 아래와 같다.<img src={process.env.PUBLIC_URL + '/logo.png'} />
a.com
경로에 배포하면 문제 없지만 http://a.com/어떤경로/
경로에 배포하면 파일을 찾을 수 없다고 나올 수 있다. 이때 /어떤경로/
를 뜻하는 process.env.PUBLIC_URL
를 더해주면 된다고 한다. (RCA) // b.js
let a = 10;
export default a // 변수명을 적어준다.
// a.js
import isA from './data.js'; // js는 생략해도 가능
❗️ ✍️ 가져올 때 default로 내보냈는데 {}
를 사용해서 {isA}
이런식으로 가져오니 오류가 발생했다. 주의하자.
export{변수1, 변수2}
와 같이 해야한다.import { a as isA } from "my-module.js"
과 같이 따로 직접 지정을 할 수 있지 않을까? 필요할 때 알아봐야 겠다.// b.js
let a = 10;
let b = 10;
export { a, b };
// a.js
import { a, b } from './data';
📌 과제)
기존의 상품 리스트를 보여주는 코드는 아래와 같았다.
<Container>
<Row>
<Col>
<img
src='https://codingapple1.github.io/shop/shoes1.jpg'
alt='shoes1'
width='80%'
/>{' '}
<h4>{shoes[0].title}</h4> <p>{shoes[0].content}</p>
</Col>
<Col>
<img
src='https://codingapple1.github.io/shop/shoes2.jpg'
alt='shoes2'
width='80%'
/>{' '}
<h4>{shoes[1].title}</h4> <p>{shoes[1].content}</p>
</Col>
<Col>
<img
src='https://codingapple1.github.io/shop/shoes3.jpg'
alt='shoes3'
width='80%'
/>{' '}
<h4>{shoes[2].title}</h4> <p>{shoes[2].content}</p>
</Col>
</Row>
</Container>;
여기서 Component를 만들어서 따로 분리해 보았다. ▼
// App.js
<Container>
<Row>
{shoes.map((list, i) => ( // 1)
<Product shoes={shoes} i={i} key={shoes[i].id}></Product>
))}
</Row>
</Container>
// Product
function Product({ shoes, i }) { // 2)
return (
<Col>
<img
src={`https://codingapple1.github.io/shop/shoes${i + 1}.jpg`} // 3)
alt='shoes'
width='80%'
/>{' '}
<h4>{shoes[i].title}</h4> <p>{shoes[i].content}</p> // 3)
</Col>
);
}
먼저 Product라는 컴포넌트를 만들고 기존 App.js 로 불러올 수 있도록 export, import 해준다.
1) Product 컴포넌트가 중복적으로 사용되지 않도록 map()
을 사용했다.
또, useState를 통해 받아온 데이터를 props로 넘겨 주었다. 이 때 키도 같이 넘겨준다.
2) Product의 파일에서 해당하는 데이터를 참조할 수 있도록 props를 받아온다.
여기서 props를 생략, 간단하게 가져오기 위해 { shoes, i }
와 같이 할당해 보았다.
3) 과 같이 map()
을 통해 받아온 데이터와 인덱스 데이터를 넣어줌으로써 동적으로 데이터가 바인딩 되도록 구현해 보았다. 다행히 잘 작동되는 것을 볼 수 있었다. 😀
페이지를 나누어서 사용자에게 각각의 페이지를 보여준다고 가정한다.
리액트를 사용하지 않았을 경우
: html 파일을 만들고 상세페이지 내용을 채운 뒤 html 파일을 전송한다.
리액트를 사용할 경우
: 리액트는 기본적으로 SPA 로써, html을 하나만 사용한다. (index.html)
따라서 디테일 페이지를 컴포넌트로 만들어 놓고 상세페이지 내용을 채운 뒤 기존 html을 비우고 원하는 페이지(컴포넌트)를 보여준다.
📌 이때, 페이지를 구분하는 라우팅을 쉽게 할 수 있도록 도와주는 리액트 라이브러리(react-router-dom)를 사용할 수 있겠다.
import { Routes, Route, Link } from 'react-router-dom';
<Routes>
<Route
path='/'
element={
<>
...
</>
}
/>
<Route path='/detail' element={<div>상세페이지</div>} />
</Routes>
/detail
인지 혹은 /about
등.. 인지 알 수가 없다.<Link>
태그를 사용하자.<Link to='/'>홈</Link>
<Link to='detail'>상세페이지</Link>
📌 과제) 컴포넌트 분리하기
function App() {
let [shoes] = useState(data);
return (
<div className='App'>
<Navbar bg='dark' variant='dark'>
<Container>
<Navbar.Brand href='#home'>ShoeShop</Navbar.Brand>
<Nav className='me-auto'>
<Link className='nav-menu' to='/'>
Home
</Link>
<Link className='nav-menu' to='detail'>
Detail
</Link>
</Nav>
</Container>
</Navbar>
<Routes>
<Route path='/' element={<Home shoes={shoes} />} />
<Route path='/detail' element={<Detail />} />
</Routes>
</div>
);
}
<Routes>
<Route>
<Link>
를 통해서 라우팅을 구현했다.<Home>
<Detail>
컴포넌트를 분리해서 보기쉽게 작성해 보았다. 😀 useNavigate
훅은 페이지의 이동을 도와준다.
import { Routes, Route, Link, useNavigate, Outlet } from 'react-router-dom';
<Navbar bg='dark' variant='dark'>
<Container>
<Navbar.Brand href='#home'>ShoeShop</Navbar.Brand>
<Nav className='me-auto'>
<Nav.Link
onClick={() => {
navigate('/');
}}
className='nav-menu'
to='/'
>
Home
</Nav.Link>
<Nav.Link
onClick={() => {
navigate('/detail');
}}
className='nav-menu'
to='detail'
>
Detail
</Nav.Link>
</Nav>
</Container>
</Navbar>
유효하지 않은 페이지에 접근했을 때 미리 만들어둔 페이지를 보이도록 한다.
path='*'
을 이용한다.<Route path='*' element={<div>없는 페이지 입니다.</div>} />
/about
페이지 안에서 /about/member
페이지와 /about/location
페이지 등을 보여주고 싶을 때// 아래 두 가지 코드는 같은 동작을 한다.
// 1)
<Route path='/about/' element={<About />} />
<Route path='member' element={<div>멤버정보</div>} />
<Route path='/about/location' element={<About />} />
//2) nested
<Route path='/about/' element={<About />}>
<Route path='member' element={<div>멤버정보</div>} /> // /about/member
<Route path='location' element={<About />} /> // /about/location
</Route>
// About
const About = () => {
return (
<div>
<h4>About 페이지 / 회사 정보</h4>
<Outlet></Outlet>
</div>
);
};
/about/member
경로로 접속할 경우 element가 2개가 보이게 된다.( about
과 about/member
)<Outlet>
을 통해서 <About>
내부 어디에 보여줄지 작성을 해주자.<Outlet>
은 nested routes의 element 를 보여주는 장소이다.📌 과제) nested routes 활용하기
<Route path='/event/' element={<Event />}>
<Route path='one' element={<p>첫 주문시 5% 할인쿠폰 지급</p>} />
<Route path='two' element={<p>생일기념 쿠폰받기</p>} />
</Route>
const Event = () => {
return (
<div>
<h4>오늘의 이벤트</h4>
<Outlet></Outlet>
</div>
);
};
✍️ 리액트 라우터
뒤로가기 버튼 이용이 가능해진다.
페이지 이동이 쉽다. (UI 스위치 조작이 쉽다.)✍️ nested 는 언제 사용할까?
여러 유사한 페이지가 필요할 때 사용하면 좋다.
스타일컴포넌트 사용하기
npm install styled-components
import styled from 'styled-components'
ex.)
let YellowBtn = styled.button`
background: ${(props) => props.bg};
color: ${(props) => (props.bg == 'blue' ? 'white' : 'black')};
padding: 10px;
`;
<YellowBtn bg='blue'>버튼</YellowBtn>
✍️ 스타일컴포넌트의 장점 : 스타일이 다른 js파일로 오염되지 않는다.(css module로도 가능) 추가문법을 통해 props로 재활용이 가능하다.
→ 리액트는 코드를 하나로 합쳐주므로 style을 모든 곳에서 가져다 쓸 수 있기 때문에 스타일이 겹치는 일이 발생할 수 있다. 하지만 스타일컴포넌트에서 사용되는 스타일은 해당 페이지 내부에서만 사용되므로 다른 파일로 오염되는 것을 방지할 수 있다.
✍️ 스타일컴포넌트의 단점 : JS파일이 복잡해지고, 이 컴포넌트가 styled인지 일반 컴포넌트인지 구분이 어려워진다. 라이브러리 지식이 필요하다. JS파일간 중복 디자인이 많이 필요하면 import해와서 사용할 수 있는데, 그럼 기존 CSS사용과 크게 다르지 않다는 점이 있다.
따라서 상황에 따라 어떤 방법으로 스타일을 적용할 건지 고민해볼 필요가 있겠다! 🤔