react-hook-form을 사용해서 checkbox 구현하기

Kaia·2022년 9월 28일
0

로직 수정 (22.09.30)

const useTerms = () => {
    const [termList, setTermList] = useState<any>([]);
    const [checkList, setCheckList] = useState<any>([])

    const [isActive, setActive] = useState<boolean>(false);

    const checkAll = (groupIdx:number) => {
        setCheckList((prev:any) => {
            const arr = [...prev]
            arr[groupIdx].all = !prev[groupIdx].all;
            arr[groupIdx].subAgrees.map((item:any, i:number) => item[i] = arr[groupIdx].all)
            return arr
        })
    }

    const checkItem = (groupIdx:number, subIdx:number) => {
        setCheckList((prev:any) => {
            const arr = [...prev]
            arr[groupIdx].subAgrees[subIdx][subIdx] = !prev[groupIdx].subAgrees[subIdx][subIdx];
            arr[groupIdx].all = arr[groupIdx].subAgrees.every((item:any, i:number) => item[i]);
            return arr
        })
    }

    const agreeTerms = () => { // isActive 로 대체
        const arr = checkList.map((item:any) => item.all)
        return validateAllChecked(arr) ? true : console.error('모두 동의해주세요');
    }

    const initList = () => {
        const term = TERMS_CONTENTS.terms.reduce((acc:any, cur:any, i:number) => {
            acc.push({ text : cur.text, subAgrees : [] })
            cur.subAgrees.map((item:any,idx:number) => { // for each 써도 되는데 map ?
                acc[i].subAgrees.push({ text : cur.subAgrees[idx].text })
            })
            return acc
        },[])
        const check = TERMS_CONTENTS.terms.reduce((acc:any, cur:any, i:number) => {
            acc.push({ all : false, subAgrees : [] })
            cur.subAgrees.map((item:any,idx:number) => {
                acc[i].subAgrees.push({ [idx] : false })
            })
            return acc
        },[])
        setCheckList(check);
        setTermList(term);
    }

    useEffect(() => {
        setActive(checkList.every((item:any) => item.all));
    },[checkList])

    useEffect(() => {
        initList();
    },[])
}

쉬운 듯 쉽지 않았던...

import React, {useEffect, useState} from "react";
import {useForm} from "react-hook-form";

interface ITerms {
    isOpen: boolean;
    children?: React.ReactNode;
    onClose?: () => void;
    agreeTerms?: any;
}

const Terms = (props:ITerms) => {
    const {register, handleSubmit} = useForm();
    const [allFlag, setAllFlag] = useState<boolean>(false)
    const [termsFlag, setTermsFlag] = useState<boolean[]>([false,false,false])
    const exList = ['1', '2','3']

    const toggleCheck = (e:any, index:number) => {
        setTermsFlag((prev:any) => {
            const arr = { ...prev };
            arr[index] = !prev[index];
            return arr;
        });
    };


    const selectAll = (e:any) => {
        setAllFlag(e.target.checked);
        setTermsFlag((prev:any) => {
            Object.keys(prev).map((item) => prev[item] = e.target.checked)
           return {
               ...prev
           }
        });
    };

    useEffect(() => {
        let allChecked = false;
        if (Object.values(termsFlag).every((item) => item)) {
            allChecked = true;
        }
        setAllFlag(allChecked);
    },[termsFlag])

    return <form onSubmit={handleSubmit(props.agreeTerms)}>
        <div>
            <div>
                <label>
                    <input type="checkbox" checked={allFlag} {...register('all')} onChange={selectAll}/>
                </label>
                <span>select all</span>
            </div>
            {
                exList.map((item:string,index:number) => {
                    return <div key={index}>
                        <label>
                            <input type="checkbox" checked={termsFlag[index]} {...register(item)} onChange={(e) => toggleCheck(e,index)}/>
                        </label>
                        <span>{item}</span>
                    </div>
                })
            }
        </div>
        <button><input type={"submit"} value={'apply'} /></button>
        </form>
}

export default Terms
profile
설명하지 못하는 지식은 아는 것이 아니다

0개의 댓글