본문으로 건너뛰기

버튼에 로딩 스피너를 추가

· 약 3분
arch-spatula

버튼에 로딩 스피너를 추가하는 방법입니다. button은 다양한 너비를 갖을 수 있고 또 입력한 텍스트 길이만큼 고정되어야 합니다. 로딩인 상황에 button의 너비가 줄어드는 일도 막아야 합니다.

import { ButtonWrapper, TextWrapper, LoaderWrapper } from './Button.style';
import { PulseLoader } from 'react-spinners';

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
children: React.ReactNode;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
isLoading?: boolean;
};

/** loader는 텍스트 너비가 필요해서 2개의 VisibilityWrapper 활용 */
export function Button({
children,
onClick,
isLoading = false,
...other
}: ButtonProps) {
return (
<ButtonWrapper
onClick={onClick}
disabled={isLoading}
isLoading={isLoading}
{...other}
>
<TextWrapper isLoading={isLoading}>{children}</TextWrapper>
{isLoading && (
<LoaderWrapper>
<PulseLoader
color="#ffffff"
loading
margin={4}
size={12}
speedMultiplier={0.5}
/>
</LoaderWrapper>
)}
</ButtonWrapper>
);
}

전략을 바꿨습니다. loading은 조건부 랜더링을 계속 처리합니다. 하지만 로딩하는 동안 텍스트도 조건부 스타일링으로 안보이게 만듭니다.

존재하지만 가시적으로 보이지 않게 때문에 텍스트 크기만큼 영역을 확보합니다.

import styled from '@emotion/styled';

export const ButtonWrapper = styled.button<{ isLoading: boolean }>`
all: unset;
${(props) => props.theme.fonts.body16Regular}
border-radius: 0.5rem;
border: none;
/* disabled 이면 gray가 되고 loading이면 green을 유지 */
background-color: ${(props) =>
props.disabled && !props.isLoading
? props.theme.colors.gray400
: props.theme.colors.green};
color: ${(props) => props.theme.colors.white};
height: 2.75rem;
position: relative;
width: fit-content;
min-width: 5.25rem;
display: flex;
align-items: center;
justify-content: center;
`;

export const TextWrapper = styled.span<{ isLoading: boolean }>`
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;

color: ${(props) =>
props.isLoading
? 'transparent'
: props.theme.colors.white}; /* 로딩하는 동안 text를 숨김 */
margin: 0 1rem;
`;

export const LoaderWrapper = styled.div`
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
`;

이렇게 되면 레이아웃 쉬프트 없이 버튼에 로딩 상태를 보여줄 수 있습니다.

버튼 로딩 스피너