상세페이지에 상품명 넣기
뭐가 좀 이상해졌는데 …
무튼 현재 Detail 컴포넌트는 따로 만들지 않고 해당 코드를 Route안의 element에 넣었는데
갑자기 강사님은 따로 파일을 빼서 정리를 해뒀다.
우선 App에서 Detail로 item 데이터를 전송하기 위해서 props를 이용
<Route path='/detail' element={<Detail item={item} />}/>
function Detail(props) {
return (
<div className='contain'>
<div></div>
{props.item.map((item) => {
return item})}
<div></div>
</div>
)
}
export default Detail
근데 여기서
Q. Detail.js 안에 item이라는 state를 하나 더 만들어주고 props를 하지 않으면 더 편하지 않음??
이렇게 되면 앞서 프젝했을 때처럼 당황스러운 결과가 나오게 되는데
데이터의 수정사항이 생겼을 때 예를 들어 데이터를 DB에 넣고 수정하고 조회 할 경우 문제가 생기게 된다.
그래서 꼭 데이터는 한곳에서 보관을 해야한다.
그리고 현재는 디테일 페이지에 모든 item에 대한 요소를 보여주고 있는데
원래 디테일 페이지의 의도로는 하나의 요소에 대한 정보만 보여주기를 원한다
그렇기에 의도대로 보이게 하려면 아래와 같이 작성을 해야하는데
<Route path="/detail/0" element={<Detail item={item[0]} />}
<Route path="/detail/1" element={<Detail item={item}[1] />}
<Route path="/detail/2" element={<Detail item={item}[2] />}
만약 여기서 요소가 100개 1000개 이렇게 엄청나게 많다면 힘들어질것이다.
그래서 사용할 수 있는 방법은 뭐 반복문도 있겠지만
Route적으로 해결하는 방법이 있다고 한다.
해결방법
페이지를 여러개 만들고 싶을 경우
- URL 파라미터 ( :id 와 같이 작명)
- 이렇게 할경우 /detail/아무거나 라는 의미가 된다.
- 참고로 URL 파라미터는 여러개 사용가능하다.
<Route path="/detail/:id" element={<Detail item={item[0]} />}
다만 위의 코드로 작성하게 되면
페이지의 내용은 모두 똑같은 내용으로 보이게 된다.
그래서 해결하는 방법으로는 유저가 URL 파라미터에 입력한것을 가져와야하는데
그 방법은 useParams() 를 사용하는 것.
useParams는 :id 라고 작명한 URL파라미터 값을 가져오게 된다.
import { useParams } from "react-router-dom"
import {datas} from './data'
function Detail(props) {
let {id} = useParams()
return (
<div className="contain">
<div style={{marginRight:'4px'}}>
<img className='items' src="https://images.pexels.com/photos/4602025/pexels-photo-4602025.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2" alt="" />
<p style={{marginTop:'7px'}}>{datas[id].title}</p>
<p>{datas[id].content}</p>
</div>
</div>
)
}
export default Detail
만약 사용자가 없는 숫자나 문자를 입력할 경우엔
if문을 이용해서 없다는 UI를 보여주면 된다.
우선 뭔가 많이 싹 갈아 엎었는데
데이터 자체를 먼저 변경했다.
- 기존의 내가 임의로 넣은것에서 강사님이 올린 데이터로 변경
let datas = [
{
id : 0,
title : "White and Black",
content : "Born in France",
price : 120000
},
{
id : 1,
title : "Red Knit",
content : "Born in Seoul",
price : 110000
},
{
id : 2,
title : "Grey Yordan",
content : "Born in the States",
price : 130000
}
]
let items = [
<div style={{marginRight:'4px'}}>
<img className='items' style={{height:'70%'}} src="https://codingapple1.github.io/shop/shoes1.jpg" alt="" />
<p style={{marginTop:'7px'}}>{datas[0].title}</p>
<p>{datas[0].content}</p>
</div>,
<div style={{marginRight:'4px', marginLeft:'2px'}}>
<img className='items' style={{height:'70%'}} src="https://codingapple1.github.io/shop/shoes2.jpg" alt="" />
<p style={{marginTop:'7px'}}>{datas[1].title}</p>
<p>{datas[1].content}</p>
</div>,
<div style={{marginLeft:'4px'}}>
<img className='items' style={{height:'70%'}} src="https://codingapple1.github.io/shop/shoes3.jpg" alt="" />
<p style={{marginTop:'7px'}}>{datas[2].title}</p>
<p>{datas[2].content}</p>
</div>
]
export {items, datas}
디테일 페이지 변경
- 원래는 이상하게 디테일 페이지에도 Item 들을 모두 넣은 페이지로 만들어 놨었어서
- 새롭게 변경한 페이지로는 해당 아이템 하나에 대한 페이지로 만들어놨다.
import { useParams } from "react-router-dom"
import {datas} from './data'
function Detail(props) {
let {id} = useParams()
let data = props.datas.find((data)=> {
console.log(data);
return data.id === Number(id)
})
let dataId = data.id+1
return (
<div style={{display:'flex', justifyContent:'center',alignItems:'center'}}>
<div style={{marginRight:'4px'}}>
<img className='items' style={{height:'50%'}} src={'https://codingapple1.github.io/shop/shoes' + dataId +'.jpg'} alt="" />
<p style={{marginTop:'7px'}}>{datas[data.id].title}</p>
<p>{datas[data.id].content}</p>
</div>
</div>
)
}
export default Detail
그리고 App.js내의 해당 버튼을 누르면 우선 현재 item에 대한 리스트 정렬을 reverse() 하도록 해서 버튼을 클릭시 보여지는 Item을 내림차순으로 정렬
let [item, setItems] = useState(items)
<button onClick={() => {
let newitem = [...item]
console.log(newitem);
newitem.reverse()
console.log(newitem);
setItems(newitem)
}}>
반전 버튼
</button>
강사님이 내준 과제해결로는 useParams()를 사용해서 주소창에 입력한 값을 id라는 변수에 넣고 props를 해온 data에 해당 하는 id와 useParams의 값을 담은 변수 id와 일치 하다면 찾아내는 find array helper method를 사용하여 변수에 담아 보이도록 하였음.
- 여기서 useParams를 담는 변수의 이름은 중괄호로 감싸줘야하는 것 같다.
import { useParams } from "react-router-dom"
import {datas} from './data'
function Detail(props) {
let {id} = useParams()
let data = props.datas.find((data)=> {
console.log(data);
return data.id === Number(id)
})
let dataId = data.id+1
return (
<div style={{display:'flex', justifyContent:'center',alignItems:'center'}}>
<div style={{marginRight:'4px'}}>
<img className='items' style={{height:'50%'}} src={'https://codingapple1.github.io/shop/shoes' + dataId +'.jpg'} alt="" />
<p style={{marginTop:'7px'}}>{datas[data.id].title}</p>
<p>{datas[data.id].content}</p>
</div>
</div>
)
}
export default Detail
styled-components 사용하기
- npm install styled-components
- 사용할 곳에서 import 해오기
import styled from 'styled-components'
styled-components 를 사용하는 이유
- 기존에 버튼을 하나 생성하고 꾸민다면 className을 넣고 CSS파일에 가야한다.
<button className='???'>버튼</button>
- 그런데 styled-components를 사용하면 JS파일에서 전부 해결이 가능하다.
사용하는 방법
- 사용하려는 곳에서 임의의 변수에다가 styeld 이후 생성하고자 하는 태그를 작성후 백틱 사이에 css넣는 것처럼 작성해주면 된다. (그러면 해당 태그 생성과 동시에 CSS적용)
- 아래는 버튼 태그 생성
- 사실은 하나의 스타일이 입혀진 컴포넌트를 생성한 것이라고 보면 된다고 한다.
- 여기서 중요한 점은 해당 변수의 이름의 단어별 첫글자는 무조건 대문자로 해야 된다. (컴포넌트이기 때문??)
import styled from 'styled-components'
let YellowBtn = sytled.button`
background: yellow;
color: black;
padding: 10px;
`
styled-components 장점
- CSS파일 열지 않아도 된다는 점.
- 스타일이 다른 js파일로 오염되지 않는다.
- 여기서 만약에 CSS 파일 자체를 오염되는것을 방지하려면 컴포넌트.module.css 로 작명이렇게 작명하게 되면 App.css에만 종속되게 된다.
- ex. App.css ⇒ App.module.css
- 페이지 로딩시간이 단축된다.
- 해당 페이지에 모든것이 다 있기 때문
Q. 근데 여기서 노란색 버튼이 아닌 오렌지색 버튼이 필요할 경우엔?
- props 문법을 사용하면 된다.
- 컴포넌트이기 때문에 props를 받아올 수 있다.
- 그렇기 때문에 props 데이터를 이용하여 컴포넌트를 재활용할 수 있다.
let YellowBtn = styled.button`
background: ${ props => props.bg};
color: black;
padding: 10px;
`
<Btn bg={'orange'}>버튼</Btn>
<Btn bg={'black'}>버튼</Btn>
- 여기서 props를 하는 방법이 독특한데
- ${ props ⇒ props.bg }
- 따로 이해해야 하는 부분은 아니고 외부 라이브러리 사용법이다 보니 그냥 그렇다정도
- 그리고 styled의 백틱 내부에는 JS를 사용하기 때문에 조건문 또한 가능하다.
let Btn = styled.button`
background: ${ props => props.bg }
color: ${props = props.bg === blue? 'white': 'black' }
`
<Btn bg={'orange'}>버튼</Btn>
<Btn bg={'blue'}>버튼</Btn>
styled-compoenent 단점
- JS가 길어질 수록 JS파일이 매우 복잡해진다.
- 중복스타일은 컴포넌트간 import 할텐데 CSS와 다른 바가 없다.
- 협업시 CSS담당의 숙련도 이슈
'React' 카테고리의 다른 글
React - 실시간 동작을 처리하기 위해 사용되는 라이브러리 및 도구 (0) | 2024.07.06 |
---|---|
React - 프로젝트 셋팅 (PWA, Tailwind, Router, Axios, Redux-Toolkit) (0) | 2024.02.20 |
React Part 1 - Step 3 (0) | 2023.06.25 |
React Part 1 - Step 2 (0) | 2023.06.25 |
React Part 1 - Step 1 (0) | 2023.06.25 |