혼자 적어보는 노트

프로그래머스 데브코스 TIL - Day 56 본문

스터디

프로그래머스 데브코스 TIL - Day 56

jinist 2022. 6. 5. 23:36

 

✅ 오늘의 학습

📌 React (8)

 

-  API를 활용한 프로젝트
- axios를 이용한 네트워크 API 실습

- react-router

 


 

여러 컴포넌트 한줄에 불러오기

 

작은 단위의 컴포넌트들이 들어있는 base폴더에서

컴포넌트를 가져오게되면 아래와 같이 컴포넌트마다 한 줄씩 불러와야한다.

import Header from './components/base/Header';
import Spinner from './components/base/Spinner';

가져오는 컴포넌트가 많아질 수록 길게 작성이 되는데

components폴더의 index파일을 사용하여 간결하게 작성하게 만들 수 있다.

 

[components/index.js]

export { default as Header } from './base/Header';
export { default as Spinner } from './base/Spinner';

 

[App.js]

import { Header, Spinner } from './components';

 

index.js폴더 안에 각각의 컴포넌트를 불러와서 export를 해주면

다른 컴포넌트에서 불러올 때 중괄호로 묶어서 불러올 수 있다!

 

 

ContextAPI + useReducer

이전강의에서는 context API내부에서 useState를 통해서 값을 관리하고

내부에서 값을 변경하는 함수를 생성하여 내보내주었는데

useReducer를 사용하면 업데이트 하는 항목을 내부적인 로직으로 만들어 둘 수 있다.

 

[contexts/postsProvider.js]

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useReducer,
} from 'react';

const PostContext = createContext();

export const usePostContext = () => useContext(PostContext);
// useContext hook에 담아서 전달

const reducer = (state, action) => {
  // 받는 action에 따라 상태를 어떻게 변경하여 처리할 지 작성
  switch (action.type) {
    case 'INIT_POSTS': {
      return action.payload;
    }
    case 'ADD_POST': {
      return [...state, action.payload];
    }
    case 'DELETE_POST': {
      const payload = action.payload;
      return state.filter((item) => item.id !== payload.id);
    }
    default: {
      console.error('Wrong type');
      break;
    }
  }
};

const PostProvider = ({ children, initialPosts, handleDeletePost }) => {
  const [posts, dispatch] = useReducer(reducer, initialPosts || []);
  // useReducer(reducer, 초기 상태)
  
  useEffect(() => {
    dispatch({ type: 'INIT_POSTS', payload: initialPosts || [] });
    // 사용자가 마음대로 설정해서 사용해도 됨.
  }, [initialPosts]);

  const onDeletePost = useCallback(
    // 해당 함수가 호출되면 dispatch를 통해 reducer에 정의된 로직이 실행된다.
    async (id) => {
      const payload = await handleDeletePost(id);
      dispatch({ type: 'DELETE_POST', payload });
    },
    [handleDeletePost],
  );

  return (
    <PostContext.Provider value={{ posts, onDeletePost }}>{children}</PostContext.Provider>
  );
  // 상위 컴포넌트에서 전달받은 데이터를 자식 컴포넌트에게 뿌려준다.
};

 

 

[App.js]

function App() {
  const initialPosts = useAsync(async () => {
    return await axios
      .get('https://jsonplaceholder.typicode.com/posts')
      .then((res) => res.data);
  }, []);

  const handleDeletePost = useCallback(async (id) => {
    return await axios
      .delete(`https://jsonplaceholder.typicode.com/posts/${id}`)
      .then(() => ({ id }));
  }, []);

  return (
    <PostsProvider
      initialPosts={initialPosts.value}
      handleDeletePost={handleDeletePost}
    >
      <div className="App">
        {initialPosts.isLoading ? <Spinner /> : <PostList />}
      </div>
    </PostsProvider>
  );
}

export default App;

 

데이터 흐름

1. 최상위 컴포넌트인 App에서 비동기 요청을 보내고 받은 결과 값 또는 비동기 함수를 provider를 통해 전달.

2. provider안에서 props로 받은 값 혹은 함수를 사용하여 dispatch를 하는 "새로운 함수"를 만들어서

자식요소에게 전달하기 위해 내부의 provider로 전달.

* 여기서 state는 무조건 dispatch와 action을 통해 수정된다.

3. useContext를 통해 context 내부에서 관리되고있는 state 및 state를 변경하는 함수를 꺼내서

컴포넌트에서 사용.

 

데이터가 전달되고 사용되는 과정은 위처럼 세 파트로 나눌 수 있었지만

provider로 두번 넘겨주는 과정 때문에 처음엔 조금 헷갈렸다.

 

redux와 비슷하지만 Redux처럼 스토어 하나로 처리하지 않고 provider로 감싸서 처리를 해줘야 한다는 불편함이 있었다.

 

 

 

 

 

React-router

이전에 v6을 조금 쓰다가 불편해서 v5를 사용했었는데

v6에도 익숙해지기위해 이번 강의는 v6으로 마이그레이션하여 작성해보았다.

import { Route, Routes } from 'react-router-dom';
import DefaultTemplate from '@components/template/DefaultTemplate';
import { PostsPage, PostPage, NotFoundPage } from '@pages';

function App() {
  return (
    <DefaultTemplate>
      <Routes>
        <Route path="/" element={<h1>Home</h1>} />
        <Route path="/posts" element={<PostsPage />} />
        <Route path="/posts/:postId" element={<PostPage />} />
        <Route path="*" element={<NotFoundPage />} />
      </Routes>
    </DefaultTemplate>
  );
}

export default App;

route를 작성하는 부분에 있어서 v5 -> v6 차이점은

switch가 Routes로 변경이 되고 exact를 작성하지 않아도 된다는 점

props를 통해 컴포넌트를 전달한다는 점이다.

 

DefaultTemplate

이전에는 상단 메뉴와같이 고정적으로 들어가는 것은 그냥 App컴포넌트 상단에 작성을 하였는데

DefaultTemplate를 사용하여 App내부의 Routes를 감싸서 따로 관리할 수 있다는 점을 알게 되었다.

const DefaultTemplate = ({ children }) => {
  return (
    <div>
      <Menu />
      <main>{children}</main>
    </div>
  );
};

 

 


✍ 느낀 점 

React 기본 강의는 이번 강의가 마지막이고 이제 배운 것을 활용해서 프로젝트를 만들어야한다.

이전에 children을 사용해서 무언가를 만드는 것이 조금 미흡했었는데

강의에서 사례를 많이 보여주셔서 앞으로 전보다는 활용을 많이 할 수 있을 듯 했다.

이전에 혼자서 공부를 했었을 때는 검색이나 여러 시행착오를 겪으면서 작성을 했었고

심지어 진땀빼며 작성한 코드들도 효율성 측면에서 좋지 않다고 느꼈었는데

이번 리액트 강의를 듣고나니 약간 지름길을 알게 된 것 같은 느낌이었다. 그만큼 많은 도움이 되었다!!

Comments