장바구니 같은 화면을 보면 개별로 체크박스 버튼이 있고 전체를 체크하는 체크박스가 있다.ㅁ
전체를 체크하는 체크박스를 클릭하면 개별 체크박스가 전부 클릭되도록 하려한다.
redux, immer를 사용하고 있고, react hook을 이용해 개발을 진행하고 있다.
방법은 다음과 같이 했다.
1. 개별, 전체 선택시 ID를 배열로 저장(변수를 checkItems 함)
2. 삭제 클릭 시 저장되어 있는 ID배열을 이용해 삭제 시도
포인트:
1) 전체선택 시, 현재 보여지고 있는 목록의 ID를 가져와 배열을 담는다
2) 개별 선택을 저장하고 있는 checkItems 안의 내용을 비교하여 값이 있으면 체크박스에 체크되어 있도록 함
reducer에 다음의 데이터를 등록한다
import produce from "immer";
export const initialState = {
posts: [{
id: 1
, title: "test1"
}, {
id: 2
, title: "test2"
}, {
id: 3
, title: "test3"
}]
}
export const REMOVE_BOOKMARK_TEST = "REMOVE_BOOKMARK_TEST"
export default (state = initialState, action) => {
return produce(state, (draft) => {
switch (action.type) {
case REMOVE_BOOKMARK_TEST: {
action.data.checkeds.forEach(function (v) {
const idx = draft.posts.findIndex(function (o) {
return o.id === v
})
draft.posts.splice(idx, 1)
})
break
}
}
})
}
화면에 보일 컴포넌트
import {useDispatch, useSelector} from "react-redux";
import React, {useEffect, useState} from "react";
import {Button, Form} from "react-bootstrap";
import {REMOVE_BOOKMARK_TEST} from "../../reducers/test/sample";
const CheckboxSample = () => {
const dispatch = useDispatch()
const {posts} = useSelector(state => state.sample)
// checked 된 것들
const [checkItems, setCheckItems] = useState([])
// 개별선택
function checkHandler(checked, id) {
if(checked) {
setCheckItems([...checkItems, id])
} else {
// 체크해제
setCheckItems(checkItems.filter(o=>o!==id))
}
}
// 전체선택
function checkAllHandler(checked) {
if(checked) {
const ids = []
posts.forEach(v => ids.push(v.id))
setCheckItems(ids)
} else {
setCheckItems([])
}
}
function deleteHandler() {
dispatch({
type: REMOVE_BOOKMARK_TEST
, data: {checkItems: checkItems}
})
}
useEffect(() => {
console.log(checkItems)
}, [checkItems])
return (
<div style={{padding: "10px"}}>
<h1>test</h1>
<div>
<Form.Check
type={"checkbox"}
label={"전체선택"}
onChange={(e) => checkAllHandler(e.target.checked)}
// checked={}
>
</Form.Check>
<Button
className={"baseButton"}
variant={"default"}
size={"sm"}
onClick={deleteHandler}>
삭제
</Button>
</div>
<div>
{posts.map(o => (
<div key={o.id}>
<span>
<Form.Check
type={"checkbox"}
onChange={(e) => checkHandler(e.target.checked, o.id)}
checked={checkItems.indexOf(o.id) >= 0 ? true : false}
>
</Form.Check>
체크
</span>
<span>o.title</span>
</div>
))}
</div>
</div>
)
}
export default CheckboxSample
모니터링을 위해 다음을 추가해서 로그를 찍는다
useEffect(() => {
console.log(checkItems)
}, [checkItems])
checkHandler를 이용해 개별체크를 하며, 체크결과가 true라면 checkItems에 저장한다.
// 개별선택
function checkHandler(checked, id) {
if(checked) {
setCheckItems([...checkItems, id])
} else {
// 체크해제
setCheckItems(checkItems.filter(o=>o!==id))
}
}
...
return (
...
<Form.Check
type={"checkbox"}
onChange={(e) => checkHandler(e.target.checked, o.id)}
checked={checkItems.indexOf(o.id) >= 0 ? true : false}
>
</Form.Check>
...
)
전체 선택 시, 현재 목록의 ID를 수집하여 저장하고, 선택해제 시 초기화한다
// 전체선택
function checkAllHandler(checked) {
if(checked) {
const ids = []
posts.forEach(v => ids.push(v.id))
setCheckItems(ids)
} else {
setCheckItems([])
}
}
...
return (
...
<Form.Check
type={"checkbox"}
label={"전체선택"}
onChange={(e) => checkAllHandler(e.target.checked)}
// checked={}
>
</Form.Check>
...
)
두번째와 세번쨰를 선택하면 로그에 다음과 같이 찍힌다.
전체선택 시, [1,2,3] 으로 저장되는걸 확인할 수 있다
삭제기능
// 개별삭제
function deleteHandler() {
dispatch({
type: REMOVE_BOOKMARK_TEST
, data: {checkItems: checkItems}
})
// 초기화
setCheckItems([])
}
REMOVE_BOOKMARK_TEST 를 호출하여 삭제 한다.
삭제후에는 checkItems를 초기화한다
삭제를 처리하는 reducer에서는 다음과 같이 처리한다.
(draft는 immer를 사용해서이고 return { ... state} 방식으로 해도 무방)
...
case REMOVE_BOOKMARK_TEST: {
action.data.checkItems.forEach(function (v) {
const idx = draft.posts.findIndex(function (o) {
return o.id === v
})
draft.posts.splice(idx, 1)
})
break
}
...
삭제하려는 index를 찾아내어 splice로 삭제한다.
(DB에 연결되어 있는거라면 reduxSaga 등 추가코딩이 필요)
수행한 후 결과를 보면 다음과 같이 삭제되어 있음을 확인할 수 있다.
구글 extends 를 이용해 state 변경내역 확인
끝.
'공부 > 프로그래밍' 카테고리의 다른 글
[google map api] geocoder 사용 시 REQUEST_DENIED 나올때 (0) | 2020.10.14 |
---|---|
[react] 개발 구성 시 필요한 패키지 정리(업데이트중) (0) | 2020.10.13 |
[springboot] jpa 2개이상 DB사용(querydsl 설정 포함) (1) | 2020.09.17 |
[airflow] GCS(Google Cloud Storage) 파일을 BigQuery에 저장하기 (0) | 2020.09.09 |
[airflow] Mysql의 캐릭터셋(charset)이 euc-kr 일 때(혹은 로드시 can't decode byte 0xb5에러가 날때) (0) | 2020.09.07 |
댓글