비동기 함수를 사용한다면, 항상 대기중인 경우가 생긴다.
0.1초, 길게는 1초 동안의 그 시간동안, 멈춰있다면, 한국인의 유저경험에는 충족치 않을것이다...!
그 짧은 시간이라도, 항상 로딩 State 를 적용하여, 로딩 시간동안 무언가 행동을 보여주도록 하자
1. 로딩 스테이트 Slice 만들기 with redux-toolkit
redux-toolkit 을 사용한다면, UI(ui를 띄우는) State 를 만들어서,
그에따라, 로딩, Modal 등의 알림창이 나오는 형태를 만들면 편하고 훌륭하다.
// ui 전용 redux-toolkit 의 slice
import { createSlice } from "@reduxjs/toolkit";
const initialState = { getFetchLoading: false, isSignup: false };
const uiSlice = createSlice({
name: "ui",
initialState,
reducers: {
fetchLoading(state, action) {
state.getFetchLoading = action.payload;
},
signupModalOn(state, action) {
state.isSignup = action.payload;
},
},
});
export const uiActions = uiSlice.actions;
export default uiSlice.reducer;
2. Redux를 사용한 Fetch의 진행중, 로딩 State 만들기
<store / quotes-actions.js >
: "페치의 시작, 끝날때, 로딩 스테이트를 업데이트시킨다."
import { quotesActions } from "./quotes-slice";
import { uiActions } from "./ui-slice";
export const getQuotesData = () => {
return async (dispatch) => {
dispatch(uiActions.fetchLoading(true)); // [로딩] 시작하면 로딩
const fetchData = async () => {
const response = await fetch(
"https://react-router-project-41a4b-default-rtdb.firebaseio.com/Quotes.json"
);
const responseData = await response.json();
const refinedData = []; // 파이어베이스 에서 오는 것 재정리
for (const key in responseData) {
refinedData.push({
id: responseData[key].id,
content: responseData[key].content,
author: responseData[key].author,
});
}
return refinedData;
};
const allQuotes = await fetchData();
dispatch(uiActions.fetchLoading(false)); // [로딩] 끝나면 로딩 끝
dispatch(quotesActions.replaceQuotes(allQuotes));
};
};
3. 로딩 스테이트에 따른, 변화 [ 페이지 컴포넌트를 잠시 완전히 교체하기 ]
import AllQuotesComponent from "../components/quotes/all-quotes";
import { useDispatch, useSelector } from "react-redux";
import { getQuotesData } from "../store/quotes-actions";
import { useEffect } from "react";
const AllQuotes = () => {
const uiState = useSelector((state) => state.uiSlice.getFetchLoading); // 로딩 스테이트를 가져온다.
const dispatch = useDispatch();
useEffect(() => {
dispatch(getQuotesData()); // 이 액션생성자 안에는, 이미 로딩 스테이트를 바꾸는 것이 포함되어있다.
}, [dispatch]);
if (uiState) {
return <p> loading</p>; // 로딩중 띄울 JSX
}
return (
<div>
<h1>명언들</h1>
<main>
<AllQuotesComponent />
</main>
</div>
);
};
export default AllQuotes;
정말 간단하지만 이런 느낌일 것이다. 다만 원하는 컴포넌트를 렌더한다던가, 멋진 문구를 넣는다던가 하면 좋겠다.
4. 로딩 스테이트에 따른, 변화 [ 컴포넌트 내에, 로딩 스피너 같은 것들 추가하기 ]
좋은 로딩 스피너가 부트스트랩에 있다.
< ui / loadingSpinner.js >
const Spinner = () => {
return (
<div className="spinner-border" role="status">
<span className="visually-hidden">Loading...</span>
</div>
);
};
export default Spinner;
이번에는 Redux 말고, State 를 사용해, 기본적인 스피너 추가를 해보자.
import Spinner from "../components/UI/ ..."
const SignupComponent= () => {
const [loading, setLoading] = useState(false)
const submitHandler = async (e) => {
e.preventDefault();
setLoading(true); // 로딩
...
const responseData = await response.json();
setLoading(false); // 로딩 끝
if (responseData.error) {
setErrorMessage(responseData.error.message);
}
};
return (
...
{loading ? ( <Spinner />) : ( // 로딩중이면, 스피너, 아니면, 버튼
<button> {isLogin ? "Login" : "Create Account"} </button>
)}
)
결론. 항상 로딩을 신경쓰자 더 나은 UX 를 위하여!
'React > React-Basic' 카테고리의 다른 글
13. 리액트 [인증] 파이어 베이스 Auth편(2) (1) | 2022.12.22 |
---|---|
12. 리액트 [인증] - 인증의 기본 원리, 파이어 베이스 Auth편(1) (0) | 2022.12.22 |
10. 현실적인 커스텀 훅 만들기, WITH. validation, onBlur 이벤트리스너 (0) | 2022.12.14 |
9. 훅의 사용 유의사항과 커스텀 훅에 대하여 (0) | 2022.12.14 |
8. State의 작동 방식 (1) | 2022.12.14 |
댓글