본문 바로가기
  • 삽질하는 자의 블로그
React/React-Basic

11. 항상 [로딩 State] 을 신경쓰자! FETCH 등의 비동기 함수를 사용한다면, with Redux

by 이게뭐당가 2022. 12. 22.

비동기 함수를 사용한다면, 항상 대기중인 경우가 생긴다.

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 를 위하여!

댓글