We want to hear from you!Take our 2021 Community Survey!
This site is no longer updated.Go to react.dev

์ฝ”๋“œ ๋ถ„ํ• 

These docs are old and wonโ€™t be updated. Go to react.dev for the new React docs.

These new documentation pages teach modern React and include live examples:

๋ฒˆ๋“ค๋ง

๋Œ€๋ถ€๋ถ„ React ์•ฑ๋“ค์€ Webpack, Rollup ๋˜๋Š” Browserify ๊ฐ™์€ ํˆด์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ํŒŒ์ผ์„ ํ•˜๋‚˜๋กœ ๋ณ‘ํ•ฉํ•œ โ€œ๋ฒˆ๋“ค ๋œโ€ ํŒŒ์ผ์„ ์›น ํŽ˜์ด์ง€์— ํฌํ•จํ•˜์—ฌ ํ•œ ๋ฒˆ์— ์ „์ฒด ์•ฑ์„ ๋กœ๋“œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ์‹œ

App

// app.js
import { add } from './math.js';

console.log(add(16, 26)); // 42
// math.js
export function add(a, b) {
  return a + b;
}

Bundle

function add(a, b) {
  return a + b;
}

console.log(add(16, 26)); // 42

์ฃผ์˜

์‹ค์ œ ๋ฒˆ๋“ค์€ ์œ„ ์˜ˆ์‹œ์™€๋Š” ๋งŽ์ด ๋‹ค๋ฅด๊ฒŒ ๋ณด์ผ ๊ฒ๋‹ˆ๋‹ค.

Create React App์ด๋‚˜ Next.js, Gatsby ํ˜น์€ ๋น„์Šทํ•œ ํˆด์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์ด ์„ค์น˜ํ•œ ์•ฑ์—์„œ Webpack์„ ๊ฐ™์ด ์„ค์น˜ํ–ˆ์„ ๊ฒ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ํˆด์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์ด ์Šค์Šค๋กœ ๋ฒˆ๋“ค๋ง์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ Webpack์˜ ์„ค์น˜ํ•˜๊ธฐ ๋ฌธ์„œ์™€ ์‹œ์ž‘ํ•˜๊ธฐ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•ด ์ฃผ์„ธ์š”.

์ฝ”๋“œ ๋ถ„ํ• 

๋ฒˆ๋“ค๋ง์€ ํ›Œ๋ฅญํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์ด ์ปค์ง€๋ฉด ๋ฒˆ๋“ค๋„ ์ปค์ง‘๋‹ˆ๋‹ค. ํŠนํžˆ ํฐ ๊ทœ๋ชจ์˜ ์„œ๋“œ ํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ์‹ค์ˆ˜๋กœ ์•ฑ์ด ์ปค์ ธ์„œ ๋กœ๋“œ ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ๋ฅผ ์ฃผ์˜ ๊นŠ๊ฒŒ ์‚ดํŽด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฒˆ๋“ค์ด ๊ฑฐ๋Œ€ํ•ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ์ข‹์€ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์€ ๋ฒˆ๋“ค์„ โ€œ๋‚˜๋ˆ„๋Š”โ€ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ ๋ถ„ํ• ์€ ๋Ÿฐํƒ€์ž„์— ์—ฌ๋Ÿฌ ๋ฒˆ๋“ค์„ ๋™์ ์œผ๋กœ ๋งŒ๋“ค๊ณ  ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ์œผ๋กœ Webpack, Rollup๊ณผ Browserify (factor-bundle) ๊ฐ™์€ ๋ฒˆ๋“ค๋Ÿฌ๊ฐ€ ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

์ฝ”๋“œ ๋ถ„ํ• ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์•ฑ์„ โ€œ์ง€์—ฐ ๋กœ๋”ฉโ€ ํ•˜๊ฒŒ ๋„์™€์ฃผ๊ณ  ์•ฑ ์‚ฌ์šฉ์ž์—๊ฒŒ ํš๊ธฐ์ ์ธ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์•ฑ์˜ ์ฝ”๋“œ ์–‘์„ ์ค„์ด์ง€ ์•Š๊ณ ๋„ ์‚ฌ์šฉ์ž๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š๊ฒŒ ํ•˜๋ฉฐ ์•ฑ์˜ ์ดˆ๊ธฐํ™” ๋กœ๋”ฉ์— ํ•„์š”ํ•œ ๋น„์šฉ์„ ์ค„์—ฌ์ค๋‹ˆ๋‹ค.

import()

์•ฑ์— ์ฝ”๋“œ ๋ถ„ํ• ์„ ๋„์ž…ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ ๋™์  import() ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

Before

import { add } from './math';

console.log(add(16, 26));

After

import("./math").then(math => {
  console.log(math.add(16, 26));
});

Webpack์ด ์ด ๊ตฌ๋ฌธ์„ ๋งŒ๋‚˜๊ฒŒ ๋˜๋ฉด ์•ฑ์˜ ์ฝ”๋“œ๋ฅผ ๋ถ„ํ• ํ•ฉ๋‹ˆ๋‹ค. Create React App์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์ด๋ฏธ Webpack์ด ๊ตฌ์„ฑ์ด ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฆ‰์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Next.js ์—ญ์‹œ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ๋ถ„ํ•  ๊ฐ€์ด๋“œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. Webpack ์„ค์ •์€ ๊ฐ€์ด๋“œ์— ์žˆ์Šต๋‹ˆ๋‹ค.

Babel์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” Babel์ด ๋™์  import๋ฅผ ์ธ์‹ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋ณ€ํ™˜ํ•˜์ง€๋Š” ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด @babel/plugin-syntax-dynamic-import๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

React.lazy

React.lazy ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋™์  import๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Before

import OtherComponent from './OtherComponent';

After

const OtherComponent = React.lazy(() => import('./OtherComponent'));

MyComponent๊ฐ€ ์ฒ˜์Œ ๋ Œ๋”๋ง ๋  ๋•Œ OtherComponent๋ฅผ ํฌํ•จํ•œ ๋ฒˆ๋“ค์„ ์ž๋™์œผ๋กœ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค.

React.lazy๋Š” ๋™์  import()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ธ์ž๋กœ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋Š” React ์ปดํฌ๋„ŒํŠธ๋ฅผ default export๋กœ ๊ฐ€์ง„ ๋ชจ๋“ˆ ๊ฐ์ฒด๊ฐ€ ์ดํ–‰๋˜๋Š” Promise๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

lazy ์ปดํฌ๋„ŒํŠธ๋Š” Suspense ์ปดํฌ๋„ŒํŠธ ํ•˜์œ„์—์„œ ๋ Œ๋”๋ง๋˜์–ด์•ผ ํ•˜๋ฉฐ, Suspense๋Š” lazy ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋“œ๋˜๊ธธ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋กœ๋”ฉ ํ™”๋ฉด๊ณผ ๊ฐ™์€ ์˜ˆ๋น„ ์ปจํ…์ธ ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
}

fallback prop์€ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋กœ๋“œ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ๋ Œ๋”๋งํ•˜๋ ค๋Š” React ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ๋ฐ›์•„๋“ค์ž…๋‹ˆ๋‹ค. Suspense ์ปดํฌ๋„ŒํŠธ๋Š” lazy ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์Œ‰๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ Suspense ์ปดํฌ๋„ŒํŠธ๋กœ ์—ฌ๋Ÿฌ lazy ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์Œ€ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </div>
  );
}

Avoiding fallbacks

Any component may suspend as a result of rendering, even components that were already shown to the user. In order for screen content to always be consistent, if an already shown component suspends, React has to hide its tree up to the closest <Suspense> boundary. However, from the userโ€™s perspective, this can be disorienting.

Consider this tab switcher:

import React, { Suspense } from 'react';
import Tabs from './Tabs';
import Glimmer from './Glimmer';

const Comments = React.lazy(() => import('./Comments'));
const Photos = React.lazy(() => import('./Photos'));

function MyComponent() {
  const [tab, setTab] = React.useState('photos');
  
  function handleTabSelect(tab) {
    setTab(tab);
  };

  return (
    <div>
      <Tabs onTabSelect={handleTabSelect} />
      <Suspense fallback={<Glimmer />}>
        {tab === 'photos' ? <Photos /> : <Comments />}
      </Suspense>
    </div>
  );
}

In this example, if tab gets changed from 'photos' to 'comments', but Comments suspends, the user will see a glimmer. This makes sense because the user no longer wants to see Photos, the Comments component is not ready to render anything, and React needs to keep the user experience consistent, so it has no choice but to show the Glimmer above.

However, sometimes this user experience is not desirable. In particular, it is sometimes better to show the โ€œoldโ€ UI while the new UI is being prepared. You can use the new startTransition API to make React do this:

function handleTabSelect(tab) {
  startTransition(() => {
    setTab(tab);
  });
}

Here, you tell React that setting tab to 'comments' is not an urgent update, but is a transition that may take some time. React will then keep the old UI in place and interactive, and will switch to showing <Comments /> when it is ready. See Transitions for more info.

Error boundaries

๋„คํŠธ์›Œํฌ ์žฅ์•  ๊ฐ™์€ ์ด์œ ๋กœ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์„ ๋กœ๋“œ์— ์‹คํŒจํ•  ๊ฒฝ์šฐ ์—๋Ÿฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋•Œ Error Boundaries๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ๊ฒฝํ—˜๊ณผ ๋ณต๊ตฌ ๊ด€๋ฆฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Error Boundary๋ฅผ ๋งŒ๋“ค๊ณ  lazy ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ๋ฉด ๋„คํŠธ์›Œํฌ ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์—๋Ÿฌ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import React, { Suspense } from 'react';
import MyErrorBoundary from './MyErrorBoundary';

const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

const MyComponent = () => (
  <div>
    <MyErrorBoundary>
      <Suspense fallback={<div>Loading...</div>}>
        <section>
          <OtherComponent />
          <AnotherComponent />
        </section>
      </Suspense>
    </MyErrorBoundary>
  </div>
);

Route-based code splitting

์•ฑ์— ์ฝ”๋“œ ๋ถ„ํ• ์„ ์–ด๋А ๊ณณ์— ๋„์ž…ํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ์กฐ๊ธˆ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„์€ ์‚ฌ์šฉ์ž์˜ ๊ฒฝํ—˜์„ ํ•ด์น˜์ง€ ์•Š์œผ๋ฉด์„œ ๋ฒˆ๋“ค์„ ๊ท ๋“ฑํ•˜๊ฒŒ ๋ถ„๋ฐฐํ•  ๊ณณ์„ ์ฐพ๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ ์ข‹์€ ์žฅ์†Œ๋Š” ๋ผ์šฐํŠธ์ž…๋‹ˆ๋‹ค. ์›น ํŽ˜์ด์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์‹œ๊ฐ„์€ ํŽ˜์ด์ง€ ์ „ํ™˜์— ์–ด๋А ์ •๋„ ๋ฐœ์ƒํ•˜๋ฉฐ ๋Œ€๋ถ€๋ถ„ ํŽ˜์ด์ง€๋ฅผ ํ•œ๋ฒˆ์— ๋ Œ๋”๋งํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์š”์†Œ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

React.lazy๋ฅผ React Router ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋ผ์šฐํŠธ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ ๋ถ„ํ• ์„ ์„ค์ •ํ•˜๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));

const App = () => (
  <Router>
    <Suspense fallback={<div>Loading...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </Suspense>
  </Router>
);

Named Exports

React.lazy๋Š” ํ˜„์žฌ default exports๋งŒ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. named exports๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด default๋กœ ์ด๋ฆ„์„ ์žฌ์ •์˜ํ•œ ์ค‘๊ฐ„ ๋ชจ๋“ˆ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด tree shaking์ด ๊ณ„์† ๋™์ž‘ํ•˜๊ณ  ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ๋Š” ๊ฐ€์ ธ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
Is this page useful?Edit this page