-
[React] react 19 버전에 대한 고찰카테고리 없음 2024. 5. 19. 16:24728x90
[React] react 19 버전에 대한 고찰
Svelte, Astro, Remix와 같은 js 프레임워크들이 떠오르고 있다. 하지만, React가 근본 프레임워크인 것은 부정할 수 없다. 신규 프레임워크들도 좋은 기술들과 성능들을 갖고 있지만, React의 역사와 유저풀은 결코 무시할 수 없기 때문이다.
지난 2024 04 25일자에 React의 19 버전이 베타 릴리스 되었다. 2022년 6월 14일 출시된 React 18.2.0 버전 이후로 처음이다. React 18 버전에서는 서버 컴포넌트가 공개되며 엄청난 이목을 끌었는데.. 19 버전은 또 얼마나 대단한 업데이트를 가져왔을지 기대되었다.
자, 지금부터 React 19 버전에 대한 변경사항을 알아보겠다.
React 19의 새로운 기능
Hooks
비동기 작업에서의 state를 업데이트하는 새로운 기능이 생겼다. 공식문서에서 제공되는 아래 코드를 살펴보자.
아래 코드는 기존에 우리가 데이터 변형을 수행하고 이에 대한 응답으로 상태를 처리하던 방법이다.
handleSubmit 내에서 useState를 통해 isPending과 같은 상태를 수동으로, 순차적으로 관리한다.
function UpdateName({}) { const [name, setName] = useState(""); const [error, setError] = useState(null); const [isPending, setIsPending] = useState(false); const handleSubmit = async () => { setIsPending(true); const error = await updateName(name); setIsPending(false); if (error) { setError(error); return; } redirect("/path"); }; return ( <div> <input value={name} onChange={(event) => setName(event.target.value)} /> <button onClick={handleSubmit} disabled={isPending}> Update </button> {error && <p>{error}</p>} </div> ); }
React 19에서는 useTransition이라는 hook을 통해 이를 보다 간편하게 처리할 수 있다.
function UpdateName({}) { const [name, setName] = useState(""); const [error, setError] = useState(null); const [isPending, startTransition] = useTransition(); const handleSubmit = () => { startTransition(async () => { const error = await updateName(name); if (error) { setError(error); return; } redirect("/path"); }) }; return ( <div> <input value={name} onChange={(event) => setName(event.target.value)} /> <button onClick={handleSubmit} disabled={isPending}> Update </button> {error && <p>{error}</p>} </div> ); }
pending state는 react query 자체적으로 지원하는 기능이기 때문에 이를 사용해 온 나로서는 크게 영향을 받지 못하겠지만, react query 없는 data fetching이나 react query 내부적으로는 큰 영향을 끼치는 변경이 될 것 같다.
data fetching이 아닌 일반적인 비동기 로직에서도 유용하게 사용할 수 있을 것으로 보인다.
useActionState라는 새로운 hook도 추가되었다.
useActionState는 작업의 결과에 따라 상태를 업데이트 할 수 있는 hook이다. (기존에는 useFormState라는 이름으로 사용되었고, useFormState는 더 이상 지원되지 않는다.)
const [state, formAction] = useActionState(fn, initialState, permalink?);
const [error, submitAction, isPending] = useActionState( async (previousState, newName) => { const error = await updateName(newName); if (error) { // 작업에 대한 어떠한 결과든 리턴해도 된다. // 여기서 우리는 에러만 리턴할 것이다. return error; } // 작업 성공 시 동작하는 코드 return null; }, null, );
예시 코드를 하나 더 보자. fromAction이 호출되면 미리 설정된 increment에 따라 state가 업데이트된다.
import { useActionState } from "react"; async function increment(previousState, formData) { return previousState + 1; } function StatefulForm({}) { const [state, formAction] = useActionState(increment, 0); return ( <form> {state} <button formAction={formAction}>Increment</button> </form> ) }
버튼을 클릭하면 state의 수가 1씩 증가될 것이다.
useFormStatus라는 새로운 hook도 추가되었다.
하나의 form이 여러 컴포넌트로 구성되어 있을 때 pending과 같은 state를 관리한다면 prop driling과 같은 현상이 발생할 수도 있다. 이를 context API를 사용하여 해결할 수도 있지만, useFromStatus를 사용한다면 더욱 쉽게 관리할 수 있다.
import {useFormStatus} from 'react-dom'; function DesignButton() { const {pending} = useFormStatus(); return <button type="submit" disabled={pending} /> }
const { pending, data, method, action } = useFormStatus();
useFormStatus는 마지막 formAction의 상태를 관리한다. 매개변수는 딱히 받지 않으며, 자신이 속한 form에 대한 상태를 쉽게 관리할 수 있는 점이 굉장한 장점이다.
useOptimistic라는 새로운 hook도 추가되었다.
useOptimistic은 낙관적 상태를 관리하게 도와준다. 비동기 동작이 진행되는 동안 미리 결과를 예상에서 적용해둔다. 이렇게 작업을 진행하는 동안에도 사용자에게 작업 수행 결과를 즉시 알려줄 수 있기 때문에 낙관적이라는 이름이 붙었다.
예를 들어 좋아요 동작을 수행할 때 유저가 좋아요를 누르면 서버에서 좋아요가 적용이 되는 동안 화면에서도 미리 좋아요 결과를 적용시켜 놓는 것이다. 업데이트가 완료되거나 오류가 발생하면 react가 알아서 이를 적용해 준다.
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
또 use라는 hook도 추가되었는데, 이는 promise나 context의 값을 읽을 수 있도록 도와준다. 쉽게 풀이하자면, js의 await와 비슷한 역할을 한다. react component의 await라고 생각하면 된다. 이를 통해 suspense를 발동시킨다. use와 가장 가까운 fallback의 suspense가 발동된다.
use는 상당히 복잡하지만 간략하게만 설명했다.
meta tag
React 19에서는 컴포넌트의 메타데이터 렌더링을 지원한다.
function BlogPost({post}) { return ( <article> <h1>{post.title}</h1> <title>{post.title}</title> <meta name="author" content="Josh" /> <link rel="author" href="https://twitter.com/joshcstory/" /> <meta name="keywords" content={post.keywords} /> <p> Eee equals em-see-squared... </p> </article> ); }
위 코드와 같이 구성하면 자동으로 meta데이터들이 head로 끌어올려진다.
이러한 방식이 지원된다면 훨씬 더 편하게 metadata를 구성할 수 있을 것이다.
compiler
아마 이 섹션이 React 19의 가장 중요한 변경사항일 것이다.
React 컴파일러는 React 코드를 javascript 코드로 변환하여 속도를 최소 2배가량 증가시킨다. 기존에는 컴포넌트의 렌더링을 최적화하기 위해 useMemo나 useCallback을 사용할 수 있었다. 그런데 이런 hook들을 남용하게 된다면 오히려 성능 최적화에 악영향을 미칠 수 있었다. 이제는 React 컴파일러가 이를 알아서 최적화한다.
정말 귀찮은 작업이고 성능 최적화를 위해 많은 고민이 필요한 작업이었지만, React 컴파일러가 자동으로 해준다.
현재 instagram에 적용중이라고한다.
마치며
React 19는 개발자 경험을 위해 많은 노력을 한 것으로 보인다. 상태를 더욱 쉽게 관리할 수 있게 되었고, 컴포넌트 최적화도 이제는 알아서 react가 도와준다. 이 덕분에 개발자들은 더욱 코드의 품질에 대해, 그리고 설계에 대해 고민할 수 있게 될 것이다.
React는 내가 가장 사랑하는 프레임워크이다. 익숙함에 속고 있는 것일지도 모르겠지만, vue나 svelte와 같은 다른 프레임워크들에 도전해 봐도 React만큼 개발할 때 편하지는 않았다. 특히 풀과 역사에 대한 부분.
앞으로도 계속 React로 개발할 예정이다.
728x90