공부/프로그래밍

[react] checkbox 전체선택하게 하기(장바구니 상품삭제 기능)

demonic_ 2020. 10. 7. 15:15

장바구니 같은 화면을 보면 개별로 체크박스 버튼이 있고 전체를 체크하는 체크박스가 있다.ㅁ

전체를 체크하는 체크박스를 클릭하면 개별 체크박스가 전부 클릭되도록 하려한다.

 

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 변경내역 확인

 

 

끝.