useState로 작성하다 중간에 react-hook-form을 추가했던 거라 input type text, number 등은 react-hook-form으로 작성했지만 radio와 checkbox는 useState로 작성되어 있었다.
API가 추가될 동안 해당 기능을 리팩토링하고자 하는 중, 과하게 복잡하게 작성했던 onChange이벤트를 발견했다.
[Feat] input type checkbox 추가하여 복수선택 가능하도록 설정 & 복수 선택하여 submit 이벤트 진행
필요한 기능 목록에서 복수선택하여 해당 회원 정보를 변경할 수 있도록 설정 복수선택해야 하는 항목이 여러개일 경우 하나의 항목만 선택하도록 조건 추가 회원정보 상세보기 화면에서 input t
jeong-ga.tistory.com
입력 이벤트를 onChange로 작성했던 코드를 react-hook-form으로 변경하는 작업을 진행하며 기존에 작성했던 checkbox 클릭 이벤트를 수정하였다.
// radio, checkbox useState
const [detailComapanyRadio, setDetailComapanyRadio] = useState({
useFlag: "1",
status: "2",
gongsaType: "reser",
});
// checkbox, 복수 선택 이벤트
const handleOnchangeGonsatype = (e) => {
const INVERTORARR = detailComapanyRadio.gongsaType.split(",");
let arr = [];
if (INVERTORARR.length == 1) {
if (detailComapanyRadio.gongsaType !== e.target.value) {
arr = [detailComapanyRadio.gongsaType, e.target.value];
}
} else {
arr = [...INVERTORARR];
if (arr.includes(e.target.value)) {
arr = arr.filter((it) => it !== e.target.value);
} else {
arr.push(e.target.value);
}
}
arr = arr.filter((it) => it !== "");
setDetailComapanyRadio({
...detailComapanyRadio,
gongsaType: arr.toString(),
});
};
// return 코드
<div className="formContentWrap">
<div className="blockLabel">
<span>사업자 공사 관리</span>
</div>
<div className="formPaddingWrap">
<input
type="checkbox"
value="emer"
id="emer"
name="gongsaType"
className="listSearchRadioInput"
checked={detailComapanyRadio.gongsaType.includes("emer")}
onChange={handleOnchangeGonsatype}
/>
<label htmlFor="emer" className="listSearchRadioLabel">
긴급
</label>
<input
type="checkbox"
value="inday"
id="inday"
name="gongsaType"
className="listSearchRadioInput"
checked={detailComapanyRadio.gongsaType.includes("inday")}
onChange={handleOnchangeGonsatype}
/>
<label htmlFor="inday" className="listSearchRadioLabel">
당일
</label>
<input
type="checkbox"
value="reser"
id="reser"
name="gongsaType"
className="listSearchRadioInput"
checked={detailComapanyRadio.gongsaType.includes("reser")}
onChange={handleOnchangeGonsatype}
/>
<label htmlFor="reser" className="listSearchRadioLabel">
예약
</label>
</div>
</div>
위 코드처럼 onChange이벤트를 통해 useState를 수정하는 코드를 작성했는데... 쓰면서도 이게 이렇게 복잡한 일인가 싶었지만.. 🥲
어쨌든 react-hook-form으로 작성하니 아주 편리해졌다.
// axios 시
servicesPostData(urlSetCompanyDetail, {
rcid: cid,
useFlag: getValues("_detailUseFlag"),
gongsaType: getValues("_gongsaType").toString(),
status: getValues("_status"),
...
// return 코드
<div className="formContentWrap">
<div className="blockLabel">
<span>사업자 공사 관리</span>
</div>
<div className="formPaddingWrap">
<input
type="checkbox"
value="emer"
id="emer"
className="listSearchRadioInput"
checked={
getValues("_gongsaType") &&
watch("_gongsaType").includes("emer")
}
{...register("_gongsaType")}
/>
<label htmlFor="emer" className="listSearchRadioLabel">
긴급
</label>
...
</div>
</div>
onChange이벤트를 따로 작성할 필요 없이 배열인 값을 string으로 변환해서 서버에 전달해주면 된다.
하위 컴포넌트가 없는 검색의 경우 훨씬 간단한 코드가 되었다.
더보기
수정 전
import { useState, useEffect } from "react";
import { useForm } from "react-hook-form";
import { servicesPostData } from "../../Services/importData";
import { urlUserlist } from "../../Services/string";
export default function ComponentListUserSearch({
setUserList,
setListPage,
searchClick,
setSearchClick,
page,
}) {
// react-hook-form 라이브러리
const { register, reset, handleSubmit } = useForm({});
const [searchData, setSearchData] = useState({
userrole: "ROLE_USER",
useFlag: "1",
});
useEffect(() => {
// searchClick을 클릭한 (true) 상태에서 동작
searchClick === true && SearchSubmit();
}, [page.activePage || searchClick]);
// 상위 컴포넌트에게 전달받은 useState의 set 함수
// setUserList가 set으로 전달받은 후 사용하기 위해 && 사용
const userList = (res) => {
setUserList && setUserList(res);
};
const listPage = (res) => {
setListPage && setListPage(res);
};
// submit 이벤트
function SearchSubmit() {
const searchDataObj = Object.entries(searchData);
// input에 입력된 값을 없애도 useState에 담긴 키가 사라지지 않아, 해당 값이 빈칸이라면 키를 제거하기 위해 filter 사용
const searchDataFilter = searchDataObj.filter((it) => it[1] !== "");
const searchDataReq = Object.fromEntries(searchDataFilter);
servicesPostData(urlUserlist, {
offset: page.getPage,
size: 15,
...searchDataReq,
}).then((res) => {
if (res.status === "fail") {
alert("검색하신 데이터가 없습니다.");
}
if (res.status === "success") {
userList(res.data);
listPage(res.page);
setSearchClick(true);
}
});
}
// 입력 이벤트
function onChangeHandle(e) {
// input Type = "date"
if (e.target.id === "createTime") {
// 날짜 포맷에 맞게 전송하기 위해 처리
const pickDate = new Date(e.target.value);
setSearchData({
...searchData,
[e.target.id]: pickDate.toISOString().slice(0, 19),
});
}
setSearchData({
...searchData,
[e.target.name.slice(1)]: e.target.value,
});
// }
}
// 초기화 이벤트
function onResetHandle(e) {
reset();
setSearchData({});
setSearchClick(false);
}
// formWrap
return (
<div className="commonBox">
<h3 className="blind">사업자관리 검색 필터</h3>
<form
className="listSearchForm formLayout"
onSubmit={handleSubmit(SearchSubmit)}
>
<div className="listSearchWrap">
<label className="blockLabel">
<span>관리번호</span>
</label>
<div>
<input
type="text"
id="uid"
name="_uid"
placeholder="관리번호를 입력해 주세요."
{...register("_uid", {
onChange: onChangeHandle,
pattern: {
value: /[0-9]/,
message: "숫자만 입력할 수 있습니다.",
},
})}
/>
</div>
</div>
<div className="listSearchWrap">
<div className="blockLabel">
<span>회원권한</span>
</div>
<div>
<input
className="listSearchRadioInput"
type="radio"
id="userroleUser"
name="_userrole"
value="ROLE_USER"
checked={searchData.userrole === "ROLE_USER"}
{...register("_userrole", {
onChange: onChangeHandle,
})}
/>
<label className="listSearchRadioLabel" htmlFor="userroleUser">
일반
</label>
<input
className="listSearchRadioInput"
type="radio"
id="userroleAdmin"
name="_userrole"
value="ROLE_USER,ROLE_ADMIN"
checked={searchData.userrole === "ROLE_USER,ROLE_ADMIN"}
{...register("_userrole", {
onChange: onChangeHandle,
})}
/>
<label className="listSearchRadioLabel" htmlFor="userroleAdmin">
관리자
</label>
</div>
</div>
<div className="listSearchWrap">
<label className="blockLabel">
<span>계약일</span>
</label>
<div>
<input
type="date"
id="createTime"
name="_createTime"
{...register("_createTime", {
onChange: onChangeHandle,
})}
/>
</div>
</div>
<div className="listSearchWrap">
<div className="blockLabel">
<span>계약관리</span>
</div>
<div>
<input
className="listSearchRadioInput"
type="radio"
id="useFlag1"
name="_userUseFlag"
value="1"
checked={searchData.useFlag === "1"}
{...register("_useFlag", {
onChange: onChangeHandle,
})}
/>
<label className="listSearchRadioLabel" htmlFor="useFlag1">
회원
</label>
<input
className="listSearchRadioInput"
type="radio"
id="useFlag0"
name="_useFlag"
value="0"
checked={searchData.useFlag === "0"}
{...register("_useFlag", {
onChange: onChangeHandle,
})}
/>
<label className="listSearchRadioLabel" htmlFor="useFlag0">
해지
</label>
</div>
</div>
<div className="listSearchButtonWrap">
<button type="reset" value="초기화" onClick={onResetHandle}>
초기화
</button>
<button type="submit" value="검색">
검색
</button>
</div>
</form>
</div>
);
}
수정후
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { servicesPostData } from "../../Services/importData";
import { urlUserlist } from "../../Services/string";
export default function ComponentListUserSearch({
setUserList,
setListPage,
searchClick,
setSearchClick,
page,
}) {
// react-hook-form 라이브러리
const { register, setValue, getValues, watch, reset, handleSubmit } =
useForm();
useEffect(() => {
setValue("_userrole", "ROLE_USER");
setValue("_useFlag", "1");
}, []);
useEffect(() => {
// searchClick을 클릭한 (true) 상태에서 동작
searchClick === true && SearchSubmit();
}, [page.activePage || searchClick]);
// 상위 컴포넌트에게 전달받은 useState의 set 함수
// setUserList가 set으로 전달받은 후 사용하기 위해 && 사용
const userList = (res) => {
setUserList && setUserList(res);
};
const listPage = (res) => {
setListPage && setListPage(res);
};
// submit 이벤트
function SearchSubmit() {
servicesPostData(urlUserlist, {
offset: page.getPage,
size: 15,
uid: getValues("_uid"),
userid: getValues("_userid"),
name: getValues("_name"),
userrole: getValues("_userrole"),
mobile: getValues("_mobile"),
createTime: getValues("_createTime"),
isCid: getValues("_isCid"),
useFlag: getValues("_useFlag"),
}).then((res) => {
if (res.status === "fail") {
alert("검색하신 데이터가 없습니다.");
}
if (res.status === "success") {
userList(res.data);
listPage(res.page);
setSearchClick(true);
}
});
}
// 초기화 이벤트
function onResetHandle(e) {
reset();
setSearchClick(false);
SearchSubmit();
}
// formWrap
return (
<div className="commonBox">
<h3 className="blind">사업자관리 검색 필터</h3>
<form
className="listSearchForm formLayout"
onSubmit={handleSubmit(SearchSubmit)}
>
<div className="listSearchWrap">
<label className="blockLabel">
<span>관리번호</span>
</label>
<div>
<input
type="text"
id="uid"
placeholder="관리번호를 입력해 주세요."
{...register("_uid", {
pattern: {
value: /[0-9]/,
message: "숫자만 입력할 수 있습니다.",
},
})}
/>
</div>
</div>
<div className="listSearchWrap">
<div className="blockLabel">
<span>회원권한</span>
</div>
<div>
<input
className="listSearchRadioInput"
type="radio"
id="userroleUser"
value="ROLE_USER"
checked={watch("_userrole") == "ROLE_USER"}
{...register("_userrole")}
/>
<label className="listSearchRadioLabel" htmlFor="userroleUser">
일반
</label>
<input
className="listSearchRadioInput"
type="radio"
id="userroleAdmin"
value="ROLE_USER,ROLE_ADMIN"
checked={watch("_userrole") === "ROLE_USER,ROLE_ADMIN"}
{...register("_userrole")}
/>
<label className="listSearchRadioLabel" htmlFor="userroleAdmin">
관리자
</label>
</div>
</div>
<div className="listSearchWrap">
<label className="blockLabel">
<span>계약일</span>
</label>
<div>
<input
type="date"
id="createTime"
{...register("_createTime", {
onChange: (e) => {
const pickDate = new Date(e.target.value);
setValue("_createTime", pickDate.toISOString().slice(0, 19));
},
})}
/>
</div>
</div>
<div className="listSearchWrap">
<div className="blockLabel">
<span>계약관리</span>
</div>
<div>
<input
className="listSearchRadioInput"
type="radio"
id="useFlag1"
value="1"
checked={watch("_useFlag") === "1"}
{...register("_useFlag")}
/>
<label className="listSearchRadioLabel" htmlFor="useFlag1">
회원
</label>
<input
className="listSearchRadioInput"
type="radio"
id="useFlag0"
value="0"
checked={watch("_useFlag") === "0"}
{...register("_useFlag")}
/>
<label className="listSearchRadioLabel" htmlFor="useFlag0">
해지
</label>
</div>
</div>
<div className="listSearchButtonWrap">
<button type="reset" value="초기화" onClick={onResetHandle}>
초기화
</button>
<button type="submit" value="검색">
검색
</button>
</div>
</form>
</div>
);
}
'front > react' 카테고리의 다른 글
react 개발환경 구축 - cra, node.js, redux 설치 (0) | 2024.02.19 |
---|---|
[Feat] 검색 및 수정 & 순위 표로 확인하기 & 표 클릭하여 수정할 수 있도록 설정 (0) | 2022.11.26 |
[Feat] input type checkbox 추가하여 복수선택 가능하도록 설정 & 복수 선택하여 submit 이벤트 진행 (0) | 2022.11.25 |
메인 색상 변환 및 레이아웃 수정 및 작업 현황 (0) | 2022.11.16 |
[style] 관리자 페이지 navigation 디자인 변경 (0) | 2022.11.01 |