리덕스 수정함수 매개변수 전달하기
리덕스에서도 수정함수에 매개변수를 전달할 수 있다.
//store.tsx
increaseAge(state, action){
state.age += action.payload;
}
//Cart.tsx
<button onClick={()=>{
dispatch(increaseAge(10));
}}>이름변경</button>
<div>{cartState.user.age}</div>
이제 매개변수를 입력할 수 있는 형식으로 함수가 바뀌었다. 이때 매개변수 위치의 변수명은 관례적으로 action 이라고 한다.
장바구니 페이지 완성하기
장바구니의 수량을 변경할 수 있도록 기능을 추가하였다.
increaseCount(state, action){
state.cart[action.payload].count += 1;
}
인덱스를 매개변수로 받아 그에 해당하는 객체의 카운트를 증가시킨다.
그 다음은 상세페이지에서 장바구니에 상품을 추가하는 코드이다.
addItem(state, action){
const existingItem = state.cart.find((item) => item.id === action.payload.id); // 아미 있는 상품이면 true
if(existingItem){
existingItem.count++;
}else{
state.cart.push({
id: action.payload.id,
name: action.payload.name,
count : 1
})
}
}
만약 카트에 이미 상품이 존재하면 그 상품의 수량만 하나 늘리고, 카트에 없는 상품이면 새로 객체를 추가하는 코드이다.
let dispatch = useDispatch();
let navigate = useNavigate();
let foundItem: Coffee | undefined = coffee.find((x) => {
return x.id == parsedId;
})
먼저 커피 객체에서 검색을 통해 요청한 id 에 해당하는 커피객체가 있는지 찾아준다.
<button
className='btn btn-primary'
onClick={()=>{
foundItem? dispatch(addItem({id: foundItem.id, name : foundItem.title}))
: <div>상품을 찾을 수 없습니다.</div>;
navigate('/cart');
}}>캐러어에 담기</button>
삼항연산자를 이용해 커피 객체가 있을 경우와 없을 경우로 나눈다. 커피가 있을 경우 addItem 함수를 호출하고 인자로 커피의 id와 name 이 담긴 객체를 넘겨준다.
bestcoffee 페이지 구현하기
이전에 배웠던 코드를 베이스로 만들수 있다.
//BestCoffee.tsx
interface BestCoffeeProps {
bestCoffees : {rank : number, title : string, img : string}[];
}
const BestCoffee : FC<BestCoffeeProps> = ({bestCoffees}) => {
return <div className='container'>
<div className='board'>
<p></p>
{
bestCoffees.map(coffee => (
<div key = {coffee.rank}>
<h1>{coffee.rank}위</h1>
<img src = {`../coffee${coffee.img}.jpg`} width = "40%"></img>
<h4>{coffee.title}</h4>
<p></p>
</div>
))
}
</div>
</div>
}
//App.tsx
<Route path='/best' element = {<BestCoffee bestCoffees = {bestCoffees}></BestCoffee>}></Route>
contact 페이지 구현
function Contact(){
return(
<div className='container'>
<div className = 'board'>
<h1>BUSINESS CONTACT</h1><p></p>
<form action='' method=''>
<div className='form-group'>
<input type = 'text' className='form-control' placeholder='이름을 입력하세요'></input><p></p>
<input type = 'text' className='form-control' placeholder='이메일을 입력하세요'></input><p></p>
<textarea className='form-control' rows = {10}></textarea><p></p>
</div>
<button type = 'submit' className='btn btn-warning'>접수하기</button>
</form>
</div>
</div>
)
}
서버는 없지만 form을 만들어둔다. 부트스트랩을 활용해서 스타일을 적용해 주고, 이름과 이베일 입력란들을 만들어준다. 만약 긴 텍스트를 입력하게 하고 싶다면 textarea 태그를 사용한다. 이 공간의 줄 수도 rows 속성으로 지정해 줄 수 있다. 마지막으로 submit 타입의 버튼도 하나 만들어준다.
리액트 디버깅 도구
크롬 개발자 도구는 리액트 코드가 아닌 변환된 html 코드가 보여서 디버깅이 어렵다. 따라서 크롬 확장 프로그램을 사용하는 것이 좋다.
React Developer Tools 라는 프로그램을 설치해보자.
이제 개발자 도구를 다시 열어보면 새로운 것들이 생겼다.
리액트 컴포넌트의 다양한 정보들을 알려주는 것을 알 수 있다.
프로파일링 이라는 기능도 있다. 녹화 기능인데 웹페이지를 조작하는 것을 녹화를 해주고 컴포넌트들의 렌더링 시간을 측정해준다.
이 기능을 활용한다면 이상하게 느린 컴포넌트등을 찾아낼 수 있다. 물론 대부분의 지연요소는 서버문제기 때문에 자주 활용할 일은 없다.
리액트 배포
리액트 자체는 그대로 배포하지 않고 특정 방법을 따라야 한다. public 에 있는 리소스는 그대로 가져가고 코드 부분은 압축을 시키는 것이다.
npm run build
이 명령어를 쳐주면 build 폴더가 생성되고 파일이 빌드된다.
이제 이 빌드된 파일을 실행해보자.
npm install -g serve
npx serve -s build
이렇게 나온다면 서버가 잘 실행된 것이다. 개발자 도구로 살펴보면 네트워크 용량이 확실히 줄어든 것을 알 수 있다.
리액트와 express 합치기
리액트와 서버를 합치는 방법은 간단하다. express 폴더 안에 리액트 폴더를 통째로 집어넣는 것이다.
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'coffeestore/build')));
//커피스토어의 빌드에 있는 path를 잡아준다.
app.get('/', function(req,res){
res.sendFile(path.join(__dirname, 'coffeestore/build/index.html'))
})
app.listen(8080, function(){
console.log('listening on 8080');
});
경로를 지정해주고 빌드 파일의 index.html을 지정해 주어야 한다. 이렇게 하면 서버에서 리액트 파일등에 접근할 수 있다. 또한 앞으로 리액트에 접속하려면 8080 포트를 사용해서 접속해야한다.
리액트 라우터와 express 라우터 연결
8080 포트를 사용하면 리액트에 요청하는것이 아닌 서버에 요청하는 것이다. 만약 /cart 와같이 url을 입력하면 찾을 수 없다고 나온다. 따라서 추가적인 라우터 설정을 해주어야 한다.
app.get('*', function(req,res){
res.sendFile(path.join(__dirname, 'coffeestore/build/index.html'))
})
url에 뭔가 입력하면 바로 서버로 가는 것이 아니라 리액트 쪽을 거쳐서 가겠다는 의미이다. * 표시는 모든 문자를 뜻한다.
서버로 바로 요청하지 않고 리액트로 일단 토스 한 후 리액트에서 다시 서버로 요청하는 방식을 사용한다.
app.get('/resapi', function(req,res){
console.log('서버 진입');
res.send('아메리카노');
})
서버에서 resapi 라는 url의 라우터를 하나 생성한다. 이 라우터는 간단하게 '아메리카노'라는 문자열을 반환한다.
이제 컴포넌트와 리액트 라우터를 하나 생성해준다.
<Route path='/reqapi' element = {<ReqApi></ReqApi>}></Route>
function ReqApi(){
let [data, setData] = useState('');
useEffect(()=>{
axios.get('http://localhost:8080/resapi')
.then((response)=>{
console.log(response);
setData(response.data);
})
})
return(
<div>
<h1>커피명: {data}</h1>
</div>
)
}
이제 리액트에서 Ajax 방식으로 서버로 부터 데이터를 다시 요청하는 것이다. 이 방식을 사용하면 사용자가 resapi로 요청을 해도 데이터가 제대로 보이게 된다. 즉 흐름은 다음과 같다.
- 사용자 url 요청
- express에서 리액트로 요청을 넘겨줌
- 리액트 라우터에서 이를 받음
- 리액트 컴포넌트에서 Ajax 방식으로 서버로 다시 요청
- express 라우터에서 요청을 처리
- 리액트 컴포넌트에서 받은 데이터를 화면에 렌더링
후기
리액트와 express를 빌드하는 방법에 대해 배웠다.
오늘로 리액트 심화 과정이 모두 끝이 났다.
키워드: 프로그래머스 데브코스, 국비지원교육, 코딩부트캠프
'프로그래머스 풀스택 데브코스 > 데브코스 TIL' 카테고리의 다른 글
웹 풀사이클 데브코스 TIL 59일차 (0) | 2024.02.15 |
---|---|
웹 풀사이클 데브코스 TIL 57일차 (0) | 2024.02.13 |
웹 풀사이클 데브코스 TIL 55일차 (0) | 2024.02.07 |
웹 풀사이클 데브코스 TIL 54일차 (0) | 2024.02.06 |
웹 풀사이클 데브코스 TIL 53일차 (0) | 2024.02.05 |