Summary of React Version 19

--- title: 'Summary of React Version 19' author: 'Hun Im' date: 2024-10-22T10:40:35+09:00 category: ['POSTS'] tags: ['Javascript', 'React'] og_image: '/images/gamer.png' keywords: ['Javascript', 'React'] --- ## Major New Features 1. Actions - Enhanced support for asynchronous functions: By using `useTransition`, you can automatically manage pending states, error handling, and optimistic updates in asynchronous functions. ```jsx const [isPending, startTransition] = useTransition() const handleSubmit = () => { startTransition(async () => { const error = await updateName(name) if (error) { setError(error) return } redirect('/path') }) } ``` 2. New Hook: `useActionState` - Easily handle common cases of Actions: Manage the results of asynchronous actions, pending states, errors, and more. ```jsx const [error, submitAction, isPending] = useActionState( async (prevState, formData) => { const error = await updateName(formData.get('name')) if (error) return error redirect('/path') return null }, null ) ``` 3. React DOM: <form> Actions and `useFormStatus` - Pass functions as `action` and `formAction` props: Automatically manage form submissions and reset the form after submission. - Added `useFormStatus` hook: Supports access to form state in design systems. ```jsx function DesignButton() { const { pending } = useFormStatus() return <button type="submit" disabled={pending} /> } ``` 4. New Hook: `useOptimistic` - Manage optimistic updates: Provide immediate feedback to users while asynchronous requests are in progress. ```jsx const [optimisticName, setOptimisticName] = useOptimistic(currentName) const submitAction = async (formData) => { const newName = formData.get('name') setOptimisticName(newName) const updatedName = await updateName(newName) onUpdateName(updatedName) } ``` 5. New API: `use` - Support reading resources during rendering: Use `use` to read promises or contexts and suspend components if necessary. ```jsx function Comments({ commentsPromise }) { const comments = use(commentsPromise) return comments.map((comment) => <p key={comment.id}>{comment}</p>) } ``` 6. React Server Components - Support for server components: Pre-render components on the server to reduce client bundle sizes and improve performance. - Server Actions: Call asynchronous functions that execute on the server from client components. ## Improvements 1. Passing ref as a Prop - No need for forwardRef: You can directly receive and use ref as a prop in functional components. ```jsx function MyInput({ placeholder, ref }) { return <input placeholder={placeholder} ref={ref} /> } ``` 2. Improved Debugging for Hydration Errors - Providing diffs: More clear messages and debugging information for errors occurring during hydration. 3. Using <Context> as a Provider - More concise context usage: You can provide context values using <Context> instead of <Context.Provider>. ```jsx const ThemeContext = createContext('') function App({ children }) { return <ThemeContext value="dark">{children}</ThemeContext> } ``` 4. Support for Cleanup Functions in ref - Return cleanup functions: You can return a cleanup function from a ref callback to execute when a component unmounts. ```jsx <input ref={(ref) => { // Executes when ref is created return () => { // Executes during ref cleanup } }} /> ``` 5. Initial Value Support in `useDeferredValue` - Setting an initial value: Add an `initialValue` option to `useDeferredValue` to specify the value used during initial rendering. ```jsx const value = useDeferredValue(deferredValue, '') ``` 6. Support for Document Metadata - Natural use of `<title>, <meta>, <link>` tags: Define document metadata directly within components, and React automatically hoists them to `<head>`. ```jsx function BlogPost({ post }) { return ( <article> <h1>{post.title}</h1> <title>{post.title}</title> <meta name="author" content="Author Name" /> </article> ) } ``` 7. Improved Stylesheet Support - Managing stylesheet precedence: Control the insertion order of stylesheets using the precedence attribute on `<link>` tags. ```jsx <link rel="stylesheet" href="style.css" precedence="high" /> ``` 8. Support for Asynchronous Scripts - Managing load order and deduplication: Declare asynchronous scripts within components, and React manages load order and deduplication. ```jsx function MyComponent() { return ( <div> <script async src="script.js" /> Content </div> ) } ``` 9. Support for Resource Preloading - Performance optimization: Provide APIs like `preload`, `prefetchDNS`, `preconnect` to optimize browser resource loading. ```jsx import { prefetchDNS, preconnect, preload, preinit } from 'react-dom' function MyComponent() { preinit('https://example.com/script.js', { as: 'script' }) preload('https://example.com/font.woff', { as: 'font' }) } ``` 10. Improved Compatibility with Third-Party Scripts and Extensions - Enhanced hydration: Prevent hydration errors caused by unexpected tags or elements, minimizing conflicts with third-party scripts or browser extensions. 11. Improved Error Reporting - Removing duplication and providing detailed information: Eliminate duplicate error messages and add new root options like `onCaughtError`, `onUncaughtError` for flexible error handling. 12. Support for Custom Elements - Improved attribute and property management: Enhanced handling of attributes and properties for custom elements, ensuring consistent behavior in client and SSR environments.
ย 
--- title: '๋ฆฌ์•กํŠธ 19๋ฒ„์ „ ์ •๋ฆฌ' author: '์ž„ํ›ˆ' date: 2024-10-22T10:40:35+09:00 category: ['POSTS'] tags: ['Javascript', 'React'] og_image: '/images/gamer.png' keywords: ['Javascript', 'React'] --- ## ์ฃผ์š” ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ 1. Actions - ๋น„๋™๊ธฐ ํ•จ์ˆ˜ ์ง€์› ๊ฐ•ํ™”: `useTransition`์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ํ•จ์ˆ˜์—์„œ ์ž๋™์œผ๋กœ pending ์ƒํƒœ, ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ, ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx const [isPending, startTransition] = useTransition() const handleSubmit = () => { startTransition(async () => { const error = await updateName(name) if (error) { setError(error) return } redirect('/path') }) } ``` 2. ์ƒˆ๋กœ์šด ํ›…: `useActionState` - Actions์˜ ๊ณตํ†ต ์‚ฌ๋ก€๋ฅผ ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌ: ๋น„๋™๊ธฐ ์•ก์…˜์˜ ๊ฒฐ๊ณผ, pending ์ƒํƒœ, ์˜ค๋ฅ˜ ๋“ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx const [error, submitAction, isPending] = useActionState( async (prevState, formData) => { const error = await updateName(formData.get('name')) if (error) return error redirect('/path') return null }, null ) ``` 3. React DOM: <form> Actions ๋ฐ `useFormStatus` - ํ•จ์ˆ˜๋ฅผ action ๋ฐ formAction prop์œผ๋กœ ์ „๋‹ฌ: ํผ ์ œ์ถœ์„ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์ œ์ถœ ํ›„ ํผ์„ ์ž๋™์œผ๋กœ ์žฌ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. - useFormStatus ํ›… ์ถ”๊ฐ€: ๋””์ž์ธ ์‹œ์Šคํ…œ์—์„œ ํผ์˜ ์ƒํƒœ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ```jsx function DesignButton() { const { pending } = useFormStatus() return <button type="submit" disabled={pending} /> } ``` 4. ์ƒˆ๋กœ์šด ํ›…: `useOptimistic` - ๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ ๊ด€๋ฆฌ: ๋น„๋™๊ธฐ ์š”์ฒญ์ด ์ง„ํ–‰๋˜๋Š” ๋™์•ˆ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ฆ‰๊ฐ์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx const [optimisticName, setOptimisticName] = useOptimistic(currentName) const submitAction = async (formData) => { const newName = formData.get('name') setOptimisticName(newName) const updatedName = await updateName(newName) onUpdateName(updatedName) } ``` 5. ์ƒˆ๋กœ์šด API: `use` - ๋ฆฌ์†Œ์Šค๋ฅผ ๋ Œ๋”๋ง ์ค‘์— ์ฝ๊ธฐ ์ง€์›: use๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ๋ฏธ์Šค๋‚˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์ฝ๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ผ์‹œ ์ค‘๋‹จ(Suspend)ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx function Comments({ commentsPromise }) { const comments = use(commentsPromise) return comments.map((comment) => <p key={comment.id}>{comment}</p>) } ``` 6. React ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ - ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ ์ง€์›: ์„œ๋ฒ„์—์„œ ์‚ฌ์ „ ๋ Œ๋”๋งํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ณ , ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. - ์„œ๋ฒ„ ์•ก์…˜: ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ## ๊ฐœ์„  ์‚ฌํ•ญ 1. ref๋ฅผ Prop์œผ๋กœ ์ „๋‹ฌ - forwardRef ๋ถˆํ•„์š”: ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ์—์„œ ref๋ฅผ ์ง์ ‘ Prop์œผ๋กœ ๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx function MyInput({ placeholder, ref }) { return <input placeholder={placeholder} ref={ref} /> } ``` 2. Hydration ์˜ค๋ฅ˜์— ๋Œ€ํ•œ ๊ฐœ์„ ๋œ ๋””๋ฒ„๊น… - ์ฐจ์ด์ (diff) ์ œ๊ณต: Hydration ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋ฅ˜์— ๋Œ€ํ•ด ๋” ๋ช…ํ™•ํ•œ ๋ฉ”์‹œ์ง€์™€ ๋””๋ฒ„๊น… ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. 3. <Context>๋ฅผ ํ”„๋กœ๋ฐ”์ด๋”๋กœ ์‚ฌ์šฉ - ๋” ๊ฐ„๊ฒฐํ•œ ์ปจํ…์ŠคํŠธ ์‚ฌ์šฉ๋ฒ•: <Context.Provider> ๋Œ€์‹  <Context>๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปจํ…์ŠคํŠธ ๊ฐ’์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx const ThemeContext = createContext('') function App({ children }) { return <ThemeContext value="dark">{children}</ThemeContext> } ``` 4. ref์˜ ์ •๋ฆฌ ํ•จ์ˆ˜ ์ง€์› - ํด๋ฆฐ์—… ํ•จ์ˆ˜ ๋ฐ˜ํ™˜: ref ์ฝœ๋ฐฑ์—์„œ ์ •๋ฆฌ(cleanup) ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ธ๋งˆ์šดํŠธ๋  ๋•Œ ์‹คํ–‰๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx <input ref={(ref) => { // ref ์ƒ์„ฑ ์‹œ ์‹คํ–‰ return () => { // ref ์ •๋ฆฌ ์‹œ ์‹คํ–‰ } }} /> ``` 5. useDeferredValue์˜ ์ดˆ๊ธฐ ๊ฐ’ ์ง€์› - ์ดˆ๊ธฐ ๊ฐ’ ์„ค์ •: useDeferredValue์— initialValue ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ดˆ๊ธฐ ๋ Œ๋”๋ง ์‹œ ์‚ฌ์šฉํ•  ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx const value = useDeferredValue(deferredValue, '') ``` 6. ๋ฌธ์„œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ง€์› - `<title>, <meta>, <link>`ํƒœ๊ทธ์˜ ์ž์—ฐ์Šค๋Ÿฌ์šด ์‚ฌ์šฉ: ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ๋ฌธ์„œ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์ •์˜ํ•˜๊ณ , React๊ฐ€ ์ด๋ฅผ `<head>`๋กœ ์ž๋™ ํ˜ธ์ด์ŠคํŒ…ํ•ฉ๋‹ˆ๋‹ค. ```jsx function BlogPost({ post }) { return ( <article> <h1>{post.title}</h1> <title>{post.title}</title> <meta name="author" content="Author Name" /> </article> ) } ``` 7. ์Šคํƒ€์ผ์‹œํŠธ ์ง€์› ๊ฐœ์„  - ์Šคํƒ€์ผ์‹œํŠธ์˜ ์šฐ์„ ์ˆœ์œ„ ๊ด€๋ฆฌ: `<link>` ํƒœ๊ทธ์— precedence ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํƒ€์ผ์‹œํŠธ์˜ ์‚ฝ์ž… ์ˆœ์„œ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ```jsx <link rel="stylesheet" href="style.css" precedence="high" /> ``` 8. ๋น„๋™๊ธฐ ์Šคํฌ๋ฆฝํŠธ ์ง€์› - ์ค‘๋ณต ์ œ๊ฑฐ ๋ฐ ๋กœ๋“œ ์ˆœ์„œ ๊ด€๋ฆฌ: ๋น„๋™๊ธฐ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ ์„ ์–ธํ•˜๊ณ , React๊ฐ€ ๋กœ๋“œ ์ˆœ์„œ์™€ ์ค‘๋ณต์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ```jsx function MyComponent() { return ( <div> <script async src="script.js" /> Content </div> ) } ``` 9. ๋ฆฌ์†Œ์Šค ํ”„๋ฆฌ๋กœ๋”ฉ ์ง€์› - ์„ฑ๋Šฅ ์ตœ์ ํ™”: preload, prefetchDNS, preconnect ๋“ฑ์˜ API๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ € ๋ฆฌ์†Œ์Šค ๋กœ๋”ฉ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค. ```jsx import { prefetchDNS, preconnect, preload, preinit } from 'react-dom' function MyComponent() { preinit('https://example.com/script.js', { as: 'script' }) preload('https://example.com/font.woff', { as: 'font' }) } ``` 10. ์„œ๋“œํŒŒํ‹ฐ ์Šคํฌ๋ฆฝํŠธ ๋ฐ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ๊ณผ์˜ ํ˜ธํ™˜์„ฑ ํ–ฅ์ƒ - Hydration ๊ฐœ์„ : ์˜ˆ๊ธฐ์น˜ ์•Š์€ ํƒœ๊ทธ๋‚˜ ์š”์†Œ๋กœ ์ธํ•œ Hydration ์˜ค๋ฅ˜๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ , ์„œ๋“œํŒŒํ‹ฐ ์Šคํฌ๋ฆฝํŠธ๋‚˜ ๋ธŒ๋ผ์šฐ์ € ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ๊ณผ์˜ ์ถฉ๋Œ์„ ์ตœ์†Œํ™”ํ•ฉ๋‹ˆ๋‹ค. 11. ์˜ค๋ฅ˜ ๋ณด๊ณ  ๊ฐœ์„  - ์ค‘๋ณต ์ œ๊ฑฐ ๋ฐ ์ƒ์„ธ ์ •๋ณด ์ œ๊ณต: ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์˜ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ , `onCaughtError`, `onUncaughtError` ๋“ฑ์˜ ์ƒˆ๋กœ์šด ๋ฃจํŠธ ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์œ ์—ฐํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. 12. ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ ์ง€์› - ์†์„ฑ ๋ฐ ํ”„๋กœํผํ‹ฐ ๊ด€๋ฆฌ ๊ฐœ์„ : ์ปค์Šคํ…€ ์—˜๋ฆฌ๋จผํŠธ์— ๋Œ€ํ•œ ์†์„ฑ๊ณผ ํ”„๋กœํผํ‹ฐ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐœ์„ ๋˜์–ด, ํด๋ผ์ด์–ธํŠธ ๋ฐ SSR ํ™˜๊ฒฝ์—์„œ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.