로그인 중 피드백 제공하기
로그인 중 피드백 제공하기
사용자가 로그인하는 동안 피드백을 제공하는 것이 중요합니다. 이를 통해 앱이 응답하지 않는 상태가 아니라 여전히 작동 중이라는 느낌을 줄 수 있습니다.
isLoading 플래그 사용하기
이를 위해 src/containers/Login.tsx
의 상태에 isLoading
플래그를 추가할 것입니다. Login
함수 컴포넌트의 상단에 다음을 추가하세요.
const [isLoading, setIsLoading] = useState(false);
그리고 로그인 중에 이 값을 업데이트할 것입니다. 따라서 handleSubmit
함수는 이제 다음과 같이 변경됩니다:
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
setIsLoading(true);
try {
await Auth.signIn(email, password);
userHasAuthenticated(true);
nav("/");
} catch (error) {
if (error instanceof Error) {
alert(error.message);
} else {
alert(String(error));
}
setIsLoading(false);
}
}
로더 버튼 만들기
이제 버튼의 상태 변화를 반영하기 위해 isLoading
플래그에 따라 다르게 렌더링할 것입니다. 하지만 이 코드는 여러 곳에서 사용될 가능성이 높습니다. 따라서 재사용 가능한 컴포넌트로 만드는 것이 합리적입니다.
frontend/
디렉토리에서 다음 명령어를 실행해 src/components/
디렉토리를 생성합니다.
$ mkdir src/components/
여기서는 API와 직접적으로 연관되지 않거나 라우트에 응답하지 않는 모든 React 컴포넌트를 저장할 것입니다.
새 파일을 만들고 src/components/LoaderButton.tsx
에 다음 내용을 추가합니다.
import Button from "react-bootstrap/Button";
import { BsArrowRepeat } from "react-icons/bs";
import "./LoaderButton.css";
export default function LoaderButton({
className = "",
disabled = false,
isLoading = false,
...props
}) {
return (
<Button
disabled={disabled || isLoading}
className={`LoaderButton ${className}`}
{...props}
>
{isLoading && <BsArrowRepeat className="spinning" />}
{props.children}
</Button>
);
}
이 컴포넌트는 isLoading
과 disabled
prop을 받습니다. 후자는 현재 Login
버튼에 있는 기능을 반영한 것입니다. isLoading
이 true
일 때 버튼이 비활성화되도록 보장합니다. 이렇게 하면 사용자가 로그인 중에 버튼을 클릭할 수 없게 됩니다.
className
prop은 이 컴포넌트에 설정된 CSS 클래스가 내부적으로 사용하는 LoaderButton
CSS 클래스를 덮어쓰지 않도록 보장합니다.
isLoading
플래그가 켜져 있을 때 아이콘을 표시합니다. 사용한 아이콘은 React Icons의 Bootstrap 아이콘 세트에서 가져온 것입니다.
로딩 아이콘에 애니메이션을 적용하기 위해 몇 가지 스타일을 추가해 보겠습니다.
src/components/LoaderButton.css
에 다음 내용을 추가합니다.
.LoaderButton {
margin-top: 12px;
}
.LoaderButton .spinning {
margin-right: 7px;
margin-bottom: 1px;
animation: spin 1s infinite linear;
}
@keyframes spin {
from {
transform: scale(1) rotate(0deg);
}
to {
transform: scale(1) rotate(360deg);
}
}
이 스타일은 아이콘을 무한히 회전시키며, 각 회전은 1초가 걸립니다. 이 스타일을 LoaderButton
의 일부로 추가함으로써 컴포넌트 내부에 자체적으로 포함시킵니다.
isLoading 플래그를 사용하여 렌더링하기
이제 새로운 컴포넌트를 Login
컨테이너에서 사용할 수 있습니다.
src/containers/Login.tsx
에서 return
문 안에 있는 <Button>
컴포넌트를 찾으세요.
<Button size="lg" type="submit" disabled={!validateForm()}>
Login
</Button>
그리고 이를 다음으로 교체하세요.
<LoaderButton
size="lg"
type="submit"
isLoading={isLoading}
disabled={!validateForm()}
>
Login
</LoaderButton>
또한, 헤더에 있는 Button
임포트를 교체하세요. 다음을 제거하세요.
import Button from "react-bootstrap/Button";
그리고 다음을 추가하세요.
import LoaderButton from "../components/LoaderButton.tsx";
이제 브라우저로 전환하여 로그인을 시도하면, 로그인이 완료되기 전의 중간 상태를 볼 수 있습니다.
에러 처리
로그인과 앱 컴포넌트에서 에러가 발생했을 때 단순히 alert
를 사용하는 것을 보셨을 겁니다. 우리는 에러 처리를 간단하게 유지할 예정입니다. 하지만 모든 에러를 한 곳에서 처리하면 나중에 도움이 될 것입니다.
이를 위해 src/lib/errorLib.ts
파일을 생성하고 다음 코드를 추가하세요.
export function onError(error: any) {
let message = String(error);
if (!(error instanceof Error) && error.message) {
message = String(error.message);
}
alert(message);
}
Auth
패키지는 다른 형식으로 에러를 던지기 때문에, 이 코드는 필요한 에러 메시지를 alert
로 표시합니다. 다른 모든 경우에는 단순히 에러 객체 자체를 alert
로 표시합니다.
이제 이 함수를 로그인 컨테이너(containers/Login.tsx
)에서 사용해 보겠습니다.
handleSubmit
함수의 catch
문을 다음과 같이 변경하세요.
catch (error) {
onError(error);
setIsLoading(false);
}
그리고 src/containers/Login.tsx
파일 상단에 새로운 에러 라이브러리를 임포트하세요.
import { onError } from "../lib/errorLib";
앱 컴포넌트에서도 비슷한 작업을 수행합니다.
onLoad
함수의 catch
문을 다음과 같이 변경하세요.
catch (error) {
if (error !== "No current user") {
onError(error);
}
}
그리고 src/App.tsx
파일 상단에 에러 라이브러리를 임포트하세요.
import { onError } from "./lib/errorLib";
가이드 후반부에서 에러 처리를 조금 더 개선할 예정입니다.
이제 앱의 회원가입 프로세스로 넘어갈 준비가 되었습니다.
For help and discussion
Comments on this chapter