button 태그의 속성중에 disabled라고 있다.
이게 뭐냐
말 그대로 버튼을 비활성화 시키는 것이다. 버튼을 비활성화 하여 사용자가 클릭하거나 상호작용 할 수 없도록 설정하는 속성이다.
기본 사용법
<button disabled>버튼</button>
-> disabled 속성이 추가되면 버튼이 회색으로 표시되며 사용자가 클릭할 수 없게 된다.
마우스 커서가 저 버튼 위에 있어도 커서 모양이 바뀌지 않는다.
비활성화 된 버튼은 폼 제출 시 서버로 전송되지 않는다. 즉 form 안에 있는 disabled 버튼은 제출되지 않는다.
이걸 동적으로 변경할 수도 있다
const button = document.querySelector('button');
// 버튼 비활성화
button.disabled = true;
// 버튼 활성화
button.disabled = false;
이 버튼에 css 스타일링을 추가할 수도 있다.
button:disabled {
background-color: lightgray;
color: darkgray;
cursor: not-allowed;
}
뭐 이런식으로 넣어주면 볼만해진다.
그럼 얘를 좀 응용해서 어디다 쓰냐?
데이터 요청 중에 버튼을 비활성화 하여 사용자가 짧은 시간 안에 두번 이상, 중복 클릭하거나 불필요한 요청을 보내지 않도록 하는데에 쓰인다.
이걸 React Query의 isLoading과 연관지어서 써보자.
예시 )
import { useQuery } from 'react-query';
function MyComponent() {
const { data, isLoading, refetch } = useQuery('fetchData', fetchDataFunction);
return (
<div>
<button onClick={refetch} disabled={isLoading}>
{isLoading ? '로딩 중...' : '데이터 새로 고침'}
</button>
{data && <div>{JSON.stringify(data)}</div>}
</div>
);
}
사용자가 버튼을 클릭하면 refetch가 호출되고 데이터 갱신을 위해 다시 요청한다.
isLoading일 때 ( isLoading은 첫 요청(마운트)) 때 . isLoading이 true 일 때 -> 즉 로딩 중일 때 버튼이 비활성화 된다. 이로 인해 사용자는 데이터가 로드되는 동안 추가 클릭을 하지 못하게 된다.
이 때 로딩중.. 과 비슷한 문구를 넣어주면 의미가 정확히 전달될 것이다.
나는 이런식으로 썼다
const { refetch } = useQuery({
queryKey: ['token'],
queryFn: async () => {
const response = await axios.get('/api/token-verify', {
withCredentials: true,
})
return response.data
},
})
const router = useRouter()
const employeeLogin = useMutation({
mutationFn: async (data: IEmployeeLoginData) => {
const tokenData = await axios.post('/api/employee-login', data)
return setToken(tokenData.data.token)
},
onSuccess: async () => {
await refetch()
toast.success('로그인 성공')
router.push('/')
},
onError: (error: any) => {
toast.error(error.response.data.message)
},
})
<button disabled={employeeLogin.isPending}
className="bg-white text-blue-600 border-blue-600 border-2 border-solid rounded-md h-12 p-3 mt-6 hover:bg-[#0A74B9] hover:text-white transition duration-300 w-full">
{employeeLogin.isPending ? (<div className="flex items-center justify-center"> <div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div> </div> ) : ('로그인')} </button>
물론 로그인이 되면 다음 페이지로 넘어가겠지만, 다시 요청을 보내 성능을 떨어뜨리거나 불필요한 요청을 또 보내지 않고 사용자의 경험을 향상시키고, 상태 관리를 편하게 하기 위해 사용했다.
저기 조건부 안의
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
원이 돌아가는 표시인데 맘에 들게 만들어진것같아서 자주 쓴다.
하여튼 React Query의 refetch, isLoading, isFetching, isPending 과 함께 써주면 좋은 button의 disabled 속성에 대해 알아보았다.