React Portal을 사용한 Modal 컴포넌트 생성React Portal을 사용해 모달을 띄워보자우선 루트 레이아웃에 모달을 넣을 div를 넣어놓았다. (id="modal-root")export default function RootLayout({ children,}: Readonly) { return ( {children} );} 그리고 Portal이라는 컴포넌트를 따로 만들어서 모달을 children으로 받고, 이 모달을 위에 넣어놓은 id modal-root의 div로 이동시킨다.'use client';import { PropsWithChildren, useEffect, useState } from 'react';import ..
useRef 함수를 호출해 ref 객체를 얻은 다음, 그 ref를 DOM 요소의 ref 속성에 설정해서 DOM 요소에 접근할 수 있었다. const NewTodo: React.FC = () => { const todoTextInputRef = useRef(); // ... return ( Todo text Add Todo ); }; export default NewTodo; useRef()로 호출해 생성한 todoTextInputRef를 input의 ref에 설정해 연결해주었다. 그런데 input의 ref에 위와 같은 오류가 발생한다. 그 이유는 타입스크립트로 작업할 때는 우리가 생성한 ref에 대해 더 많은 정보를 알려주어야 하기 때문이다. useRef로 ref객체를 생성할 시점에는 타입스크립트는 to..
테스트 테스트는 작성한 코드가 잘 작동하는 것을 검증하는 작업이다. 개발자로서 코드를 작성해서 브라우저에서 수동적으로 테스트할 수도 있지만, 이렇게 수동적인 테스트는 오류가 발생하기 쉽고 모든 시나리오를 테스트하기 어렵다. 따라서 우리는 자동화된 테스팅을 하는 것이 중요하다. 테스트 자동화는 추가적인 코드를 작성해서 애플리케이션의 메인 코드를 테스트하는 것을 의미한다. 전체 애플리케이션을 자동으로 테스트하는 코드를 작성하기 때문에 항상 모든 것을 테스트할 수 있다는 것이 장점이다. 테스트의 종류 유닛 테스트 컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는 지 검증하는 가장 작은 단위의 테스트이다. 즉, 모든 함수와 메소드에 대한 테스트 케이스를 작성하는 절차를 의미한다. 통합 ..
useMutation useMutation 훅은 데이터를 생성/업데이트/삭제 하는 쿼리에 최적화되어있다. useQuery와 달리 컴포넌트가 렌더링될 때 요청이 즉시 전송되지 않도록 할 수 있고, 필요할 때만 요청이 전송되도록 할 수 있다. const { mutate, isPending, isError, error } = useMutation({ mutationFn: createNewEvent, }); useMutaion에도 useQuery와 같이 config 객체를 전달한다. 이때 마찬가지로 mutationKey도 설정할 수 있지만 여기서는 필수 옵션이 아니다. mutation의 목적은 백엔드에 변경을 적용하는 것이지 프론트에 데이터를 가져오고 저장하는 것이 아니라 필요없다. 따라서 mutationFn만..
Lazy Loading(지연 로딩) 이란? Lazy Loading은 특정 코드를 필요할 때만 로딩하게 해준다는 개념이다. 컴포넌트, 라이브러리 같은 것들을 import 문으로 불러오는데 이 import 문들은 화면에 무언가 뜨기 전에 먼저 처리되어야 한다. 사용자에게 전달되기 전에 모든 코드가 불러와져야 한다는 의미이다. 이것은 규모가 작은 애플리케이션에서는 문제가 되지 않지만, 규모가 크고 복잡한 애플리케이션의 경우 초기에 모든 코드를 불러오려면 첫 페이지의 로딩이 느려질 수 밖에 없다. 이를 위해서 특정 컴포넌트를 필요할 때 불러올 수 있는 lazy loading을 이용할 수 있다. Lazy Loading 적용하기 import { createBrowserRouter, RouterProvider } f..
useEffect(() => { async function fetchEvents() { setIsLoading(true); const response = await fetch('http://localhost:8080/events'); if (!response.ok) { setError('Fetching events failed.'); } else { const resData = await response.json(); setFetchedEvents(resData.events); } setIsLoading(false); } fetchEvents(); }, []); 위 코드와 같이 useEffect 안에서 백엔드로부터 데이터를 받아올 수도 있고, 로딩 상태와 에러 메세지를 표시할 수 도 있다. 이렇게 작성한..
잊지 말아야 할 점! 🌟 리듀서는 부수 효과(side-effect)가 없는 순수 함수여야 하고, 동기식(synchronous)이어야 한다. 따라서 리듀서 내부에서 부수 효과를 수행하거나, http 요청을 보내는 것과 같은 비동기식 코드를 작성해서는 안된다! 🧐 그렇다면 그러한 부수 효과와 비동기 작업은 어디서 실행되어야 할까? 방법은 두 가지가 있다. 이 두 가지 방법을 모두 살펴보자. 1. 컴포넌트 내부 (useEffect 훅)에서 실행 2. action creator(액션 생성자)에서 실행 장바구니에 상품을 추가하고 삭제할 수 있는 애플리케이션이 있다고 하자. 상태 슬라이스에는 ui에 관련된 상태와 장바구니(cart)에 관련된 상태가 있다. 장바구니에 상품을 추가하고 삭제할 때 리덕스 저장소에만 반영..
return ( ); 위 컴포넌트를 예를 들어보면, 실제 DOM에 들어가는 내용은 아래와 같을 것이다. {props.message} ... 이 코드는 잘 동작하지만 의미적인 관점에서 좋지 않다. 모달은 전체 페이지 위에 표시되는 오버레이이다. 따라서 다른 모든 것 위에 있어야 하는 것이 맞다. 하지만 이 코드는 다른 HTML 코드 안에 중첩되어 있기 때문에 좋은 코드가 아니다. 따라서 모달이 깊게 중첩되지 않게, 다른 것들 위에 있어야 하려면 다음과 같은 구조가 맞다. {props.message} ... 이처럼 렌더링하려는 HTML 내용을 다른 곳으로 이동시켜 렌더링하려면 Portal을 사용하면 된다. Portal 1. 컴포넌트를 이동시킬 장소 필요 보통 public/index.html 에서 div를 추..