dispatch()
로 수정요청을 할때 데이터를 보낼수도 있다!!
빠른 결론: props.dispatch({ type : 어쩌구, payload : '안녕' })
- '안녕'이라는 데이터를 redux store까지 데이터를 실어보낼 수 있고, reducer 안에서 요청을 처리할 땐 액션.payload
라고 쓰면 보냈던 '안녕' 데이터를 사용할 수 있음
<button
onClick={() => {
props.dispatch({
type: "수량증가",
payload: { name: "kim" },
});
}}>+</button>
'kim'이라는 자료가 redux store에 전달 될 것이다.
//index.js
function reducer(state = 초기값, 액션) {
액션.payload
.
.
액션 파라미터에서 이런식으로 꺼내 쓰면된단다!!
이를 활용해 장바구니 추가 버튼을 만들것이다
function reducer(state = 초기값, 액션) {
if (액션.type === "항목추가") {
let copy = [...state];
copy.push();
return copy;
}
.
.
.
'항목추가'라는 타입이 들어오면 state의 카피본을 만들고 카피본에 어떤 데이터를 push하도록 했다.
//Detail.js
<button
className="btn btn-danger"
onClick={() => {
//let newData = [...props.info];
//newData[0] -= 1;
//props.재고변경(newData);
props.dispatch({ type: "항목추가" });
}}
>
주문하기
dispatch를 통해 type을 전달해준다, 이상태로 컴파일 하면 에러가 발생한다. 당연 Detail.js는 다른 파일이기 때문
import { connect } from "react-redux";
.
.
function state를props화(state) {
return {
상품: state.reducer,
alert: state.reducer2,
};
}
export default connect(state를props화)(Detail);
state를 props화 해주는 함수도 다시 작성해줘야한다
//Detail.js
<button
className="btn btn-danger"
onClick={() => {
// let newData = [...props.info];
//newData[0] -= 1;
//props.재고변경(newData);
props.dispatch({
type: "항목추가",
payload: { id: 2, name: "new shoes", quan: 1 },
});
}}
>
이제 payload를 통해 원하는 데이터를 담아 보낼수 있다.
function reducer(state = 초기값, 액션) {
if (액션.type === "항목추가") {
let copy = [...state];
copy.push(액션.payload);
return copy;
}
.
.
.
다시 index.js로 가서 payload로 받은 데이터를 push 해주면 된다
(reducer의 '액션' 파라미터 -> dispatch() 할때 보낸 object 의미)
실제로 payload를 통해 전달한 데이터가 주문하기 버튼을 누를때마다 들어가는것을 확인할수 있었다.
하지만 cart페이지로 넘어가면 추가한 데이터가 들어가진 않는다->개발환경에서 새로고침을 하면 redux도 초기화 되기 때문
이게 싫다면 useHistory() 훅을 써보자
<button
className="btn btn-danger"
onClick={() => {
//let newData = [...props.info];
//newData[0] -= 1;
//props.재고변경(newData);
props.dispatch({
type: "항목추가",
payload: { id: 2, name: "new shoes", quan: 1 },
});
history.push('/cart');
}}
>
주문하기 버튼을 누름과 동시에 Cart.js 페이지가 렌더링 되고 하드코딩한 데이터가 들어가게 된다ㅎㅎ
강의 내에서의 숙제
1. 주문하기를 누르면 임시상품명을 state에 추가하는데, 현재 페이지에 있는 상품명을 추가하기let [주문개수, set주문개수] = useState(0);
우선 주문개수를 저장할 state를 하나 선언했다.
<p> <InputGroup className="mb-3"> <InputGroup.Text id="inputGroup-sizing-default"> 주문 개수 </InputGroup.Text> <FormControl onChange={(e) => { set주문개수(e.target.value); }} value={주문개수} type='number' aria-label="Default" aria-describedby="inputGroup-sizing-default" /> </InputGroup> </p>
input박스를 하나 만들어 onChange를 통해 주문개수를 state에 저장, input폼은 부트스트랩 그냥 복붙했다.
<button className="btn btn-danger" onClick={() => { let newData = [...props.info]; newData[0] -= 1; props.재고변경(newData); props.dispatch({ type: "항목추가", payload: { id: findItem.id, name: findItem.title, quan: 주문개수, }, }); history.push("/cart"); }} 주문하기 </button>
기존에 findItem에 해당 품목의 데이터가 저장되어있으므로, payload에 각 데이터 오브젝트를 전달하도록 했다. quan은 아까 만든 '주문개수' state를 전달
주문하기 버튼을 눌렀을때 해당 품목과 수량이 Cart 페이지에 잘 전달이 되었다 (detail/1, detail/2 페이지에서도 동일하게 잘 작동)
2. 주문하기 버튼을 눌렀을때 같은 상품이 이미 state에 존재하면 수량만 증가 시키기
//index.js function reducer(state = 초기값, 액션) { if (액션.type === "항목추가") { let findIdx = state.findIndex((a) => { return a.name === 액션.payload.name; }); if (findIdx >= 0) { let copy = [...state]; copy[findIdx].quan = copy[findIdx].quan + 액션.payload.quan; } else { let copy = [...state]; copy.push(액션.payload); return copy; } . . .
Reducer 부분을 약간 바꿔주었다. findIndex 함수를 통해 기존 초기값 state의 이름과 payload로 들어온 이름이 같으면 해당 데이터의 인덱스를 리턴, findIdx 변수에 저장
findIdx가 0보다 크면 이미 존재하는 상품이라는 뜻이므로 payload로 받은 수량만 기존 데이터에 더해주었다.//Detail.js <button className="btn btn-danger" onClick={() => { let newData = [...props.info]; newData[0] -= 1; props.재고변경(newData); props.dispatch({ type: "항목추가", payload: { id: findItem.id, name: findItem.title, quan: Number(주문개수), }, }); history.push("/cart"); }} . . .
Detail 페이지에서 payload를 보낼때 quan 값을 Number()로 정수로 바꿔주었다. Number 함수를 쓰지않으면 quan값이 문자열로 전달되었기 때문이다.
처음에 5개를 주문하고 뒤로가서 10개를 더 주문할것이다.
동일한 상품이라 수량만 잘 증가 되었다.
다른 기능 구현
1. +, - 누르면 각각의 상품 수량 증가시키기
//Cart.js
<button
onClick={() => {
props.dispatch({
type: "수량증가",
payload: idx,
});
}}
>
+
</button>
<button
onClick={() => {
props.dispatch({ type: "수량감소", payload: idx });
}}
>
-
</button>
payload에 각 상품의 인덱스를 전달했다. 위에 map(item, idx)로 감싸서 해당 상품의 인덱스가 전달 될것이다.
//index.js
if (액션.type === "수량증가") {
let copy = [...state];
copy[액션.payload].quan++;
return copy;
} else if (액션.type === "수량감소") {
let copy = [...state];
copy[액션.payload].quan--;
if (copy[액션.payload].quan < 0) {
copy[액션.payload].quan = 0;
}
return copy;
copy인덱스에 payload로 보낸 인덱스를 넣어준다.
이제 +, - 버튼을 누르면 각각의 상품마다 동작한다.
2. 장바구니에 가격도 출력시키기
<td>{item.price * item.quan}</td>
장바구니 표에 항목을 하나 더 추가해 각 상품의 가격과 수량을 합친 총합이 나오게 했다.
각 상품의 수량과 가격에 따른 총 가격이 잘나온다
수량을 감소 시켜도 잘 작동한다
3. 장바구니 표 하단에 가격 총합 나오게 하기
Cart 컴포넌트 안에 함수를 하나 만들었다
const priceSum = () => {
let sum = 0;
for (let i = 0; i < props.상품.length; i++) {
sum += props.상품[i].quan * props.상품[i].price;
}
return sum;
};
반복문을 통해 장바구니 페이지에 있는 상품의 총 가격을 계산하게 하였다.
<div className="priceSum">{priceSum()} ₩</div>
장바구니 하단에 div태그를 만들어서 함수를 실행하기만 하면 끝
계산이 잘되서 나온다ㅎㅎ
+, - 버튼에 따라 유동적으로 가격 총합도 잘 바뀐다.
사이즈가 담긴 배열 하나 만들고 map함수로 option 태그 렌더링도 했다. 선택한 값을 state에 저장해서 또 payload에 보내면 될것
사이즈 옵션도 잘들어간다, 근데 중복된걸 또 선택하면 옵션이 덮어써진다, 중복된 상품이 들어와도 중복처리하지말고 그냥 냅둬도 괜찮을듯
출처 : https://codingapple.com/ (코딩애플님 리액트 강의)