2023. 7. 3. 14:52ㆍ프론트엔드
외주개발 하면서 별 문제가 아니라고 생각했던 문제가 드디어 직면 했다. 바로 electron에서 input 포커싱을 잃는 큰 문제 였다.
아무리… 찾아 봐도 electron을 한국에서 쓰지 않는지라 관두고 있었는데 영어로 검색하니까 바로 나왔다.. 역시 영어를 배워야 한다..
*추가: electron에는 alert대신 dialog api를 사용해서 해결 할 수 있다.
https://www.electronjs.org/docs/latest/api/dialog
관련 이슈
Can't edit input text field after window.alert()
애초에 electron에서는 alert창을 사용하는것을 권장하지 않았다. 내가 겪은 문제는..
- electron에서 alert(알림창)를 사용하면 alert창에 포커싱이 간다.
- 여기서 확인을 눌러 버리면 alert창에 유지 되던 포커싱이 input창에 돌아오지 않는 버그 발생
- 해결 하려면 다른 윈도우 창을 클릭해서 포커스를 되찾아 와야 함…
따라서 알림 창을 modal 창으로 줘서 이를 해결해 보고자 함
antd의 modal 컴포넌트를 참고 해서 코드를 작성 했다.
import { Modal } from "antd";
const AlertModal = ({ title, state, setIsModalOpen }) => {
const handleOk = () => {
state.handler();
setIsModalOpen(false);
};
const handleCancel = () => {
setIsModalOpen(false);
};
return (
<>
{state.open && (
<Modal title={title} open={state.open} onOk={handleOk} type="success">
<p>{state.message}</p>
</Modal>
)}
</>
);
};
export default AlertModal;
이를 로그인 로직 끝에 추가 했다.
기존 코드
alert(`로그인 결과 : ${result.message}`);
모달창을 적용한 코드
const [modal, setOpen] = useState({ open: false, message: "", handler:()=>{});
//로그인 로직
setOpen({
open: true,
message: "로그인 성공",
handler: () => {
//로그인 성공 시 함수 동작
});
}
});
//
위와 같이 작성하고, 컴포넌트를 추가 한다.
<AlertModal
title="로그인 결과"
state={modal}
setIsModalOpen={setOpen}
/>
와 해결했다..!! 하지만…
모달창 상태를 커스텀 훅으로 모듈화 해서 사용하기
정상적으로 다 작동은 하지만, alert를 박아 둔곳이 많아서 이를 모듈화 해서 재사용성을 높이고자 한다.
useModalState.js
import { useState } from "react";
import AlertModal from "../../component/AlertModal";
const useModalState = (title) => {
const [modal, setOpen] = useState({ open: false, message: "" ,handler:()=>{}});
const openModal = (message, handler) =>
setOpen({
open: true,
message: message,
handler,
});
return {
MyModal: () => (
<AlertModal title={title} state={modal} setIsModalOpen={setOpen} />
),
openModalFunc: openModal,
};
};
export default useModalState;
- 반복 적으로 사용되는 모달과 모달이 닫힌 후 동작하는 행동을 정의할 수 있는 함수를 같이 반환 한다.
위와 같이 쓰고 로그인 로직에서 코드를 고쳐 준다.
//타이틀을 정해준다.
//MyModal: 모달 컴포넌트
//openModalFunc: 모달을 오픈할 때의 설정을 지정하는 함수
const { MyModal, openModalFunc } = useModalState("로그인 결과");
//...
openModalFunc("로그인 성공", () => {
//로그인 성공 했을 때의 동작
);
});
//
return <>
<MyModal />
</>
굳이 모달의 상태를 객체로 관리 하지 않아도 간편하게 알아볼 수 있게 모달을 설정할 수 있다.
모듈로 분리 했으니… 여기저기 리팩토링 해야겠다.. 그럼 이만!
라고했습니다. 이제 새로운 이슈와 함께 리펙토링을 해야할 때가 온것입니다.
7.01 Modal 창 Cancel 키 먹통 이슈
Modal 관련 에러 ( emp ) #issue/Modal
- 문제 : 업무 기록 제출 시 dialog 창에 취소 버튼을 눌러도 데이터 전송 및 form 데이터 조작 불가 현상
useModalState.js 커스텀 훅 작성
import { useState } from "react";
import AlertModal from "../component/modal/AlertModal";
const initialState = {
open: false,
message: "",
okHandler: () => {},
cancelHandler: () => {},
};
const useModalState = (title) => {
const [state, setIsOpen] = useState(initialState);
const openModal = ({
message,
okHandler = () => {},
closeHandler = () => {},
}) =>
setIsOpen({
open: true,
message,
okHandler,
closeHandler,
});
const closeModal = () => {
setIsOpen((prev) => {
return { ...prev, open: false };
});
};
return {
ModalElement: () => (
<AlertModal
title={title}
isOepn={state.open}
message={state.message}
setCloseModal={closeModal}
handleOpen={state.okHandler}
handleClose={state.cancelHandler}
/>
),
openModalWithSetting: openModal,
};
};
export default useModalState;
AlertModal.js 컴포넌트
const AlertModal = ({
title,
isOepn,
setCloseModal,
message,
handleOpen = () => {},
handleClose = () => {},
}) => {
const [confirmLoading, setConfirmLoading] = useState(false);
const handleOk = async () => {
setConfirmLoading(true);
await handleOpen();
setConfirmLoading(false);
setCloseModal();
};
const handleCancel = async () => {
setConfirmLoading(true);
await handleClose();
setConfirmLoading(false);
setCloseModal();
};
return (
<>
<Modal
title={title}
open={isOepn}
onOk={handleOk}
confirmLoading={confirmLoading}
onCancel={handleCancel}
>
<p>{message}</p>
</Modal>
</>
);
};
export default AlertModal;
- OK 상황과 , CANCEL상황을 비동기로 처리할 수 있는 모달창 작성
모달 리펙토링 효과
원래의 코드(리펙토링 전)
//타이틀을 정해준다.
//MyModal: 모달 컴포넌트
//openModalFunc: 모달을 오픈할 때의 설정을 지정하는 함수
const { MyModal, openModalFunc } = useModalState("로그인 결과");
//...
openModalFunc("로그인 성공", () => {
//로그인 성공 했을 때의 동작
);
});
//
return <>
<MyModal />
</>
리펙토링 후
const { ModalElement, openModalWithSetting } = useModalState("업무기록제출");
...
openModalWithSetting({
message: "업무기록 제출을 완료하였습니다.",
okHandler: () => {
form.resetFields();
refreshHandler();
setDisabled(false);
},
});
- 객체로 매개변수를 받아, 각각 변수의 역할을 쉽게 알 수 있다. 이로인해 가독성이 높아지고, 유지보수가 용이해짐
- OK와 Cancel의 작업을 분리해서 비동기 작업을 처리 가능하게 됐음. 확실하게 Cancel 버튼을 누르면 작업이 취소됨.
'프론트엔드' 카테고리의 다른 글
React에서 관심사를 분리하는 법 (feat . customHook, router ) (0) | 2023.05.21 |
---|---|
소프트웨어 테스트 feat. react (0) | 2023.05.20 |
프론트엔드 개발자도 알면 좋은 지식 Infra (0) | 2023.05.18 |
개발자의 기본 협업 (1) | 2023.05.18 |
세션 기반 로그인에 대한 설명 (0) | 2023.03.16 |