Reactサーバーコンポーネントとは何ですか?

ちょうど1週間前、reactチームは新しいRFCについてブログに投稿しましたそれがどんな種類の動物で、なぜそれが必要なのかを理解しましょう。






それは何ですか

名前が示すように、Reactサーバーコンポーネントはサーバー上で実行されるコンポーネントです。現在、いくつかの種類のコンポーネントがあります。





  • クライアントコンポーネント





  • サーバーコンポーネント





  • ハイブリッドコンポーネント





クライアントコンポーネント

, , . . .client.js







, ( useState



"" ). . . .server.js



. , .





. . . JSX .





SSR

, SSR



Next.js



. , ? . , SSR



HTML



, . SSR



, . Server Components JSON



virtual dom



.





, , server components.





SSR server components, .





, . , .





, , .server.js







// Note.server.js - Server Component

import db from 'db.server'; 
// (A1) We import from NoteEditor.client.js - a Client Component.
import NoteEditor from 'NoteEditor.client';

function Note(props) {
  const {id, isEditing} = props;
  // (B) Can directly access server data sources during render, e.g. databases
  const note = db.posts.get(id);

  return (
    <div>
      <h1>{note.title}</h1>
      <section>{note.body}</section>
      {/* (A2) Dynamically render the editor only if necessary */}
      {isEditing 
        ? <NoteEditor note={note} />
        : null
      }
    </div>
  );
}
      
      



.





, , :





Zero-Bundle-Size Components

, , . , , . , markdown , :





// NoteWithMarkdown.js
// NOTE: *before* Server Components

import marked from 'marked'; // 35.9K (11.2K gzipped)
import sanitizeHtml from 'sanitize-html'; // 206K (63.3K gzipped)

function NoteWithMarkdown({text}) {
  const html = sanitizeHtml(marked(text));
  return (/* render */);
}
      
      



bundle 74 , server components, :





// NoteWithMarkdown.server.js - Server Component === zero bundle size

import marked from 'marked'; // zero bundle size
import sanitizeHtml from 'sanitize-html'; // zero bundle size

function NoteWithMarkdown({text}) {
  const html = sanitizeHtml(marked(text));
  return (/* render */);
}
      
      



, 74 .





Backend

, :





// Note.server.js - Server Component
import fs from 'react-fs';

function Note({id}) {
  const note = JSON.parse(fs.readFile(`${id}.json`));
  return <NoteWithMarkdown note={note} />;
}
      
      



// Note.server.js - Server Component
import db from 'db.server';

function Note({id}) {
  const note = db.notes.get(id);
  return <NoteWithMarkdown note={note} />;
}
      
      



, , 3 :





  • react-fs



    -





  • react-fetch



    -





  • react-pg



    - PostgresSql





, API server component.





Code Splitting

, Code Splitting. , , bundle React.lazy:





// PhotoRenderer.js
// NOTE: *before* Server Components

import React from 'react';

// one of these will start loading *when rendered on the client*:
const OldPhotoRenderer = React.lazy(() => import('./OldPhotoRenderer.js'));
const NewPhotoRenderer = React.lazy(() => import('./NewPhotoRenderer.js'));

function Photo(props) {
  // Switch on feature flags, logged in/out, type of content, etc:
  if (FeatureFlags.useNewPhotoRenderer) {
    return <NewPhotoRenderer {...props} />; 
  } else {
    return <OldPhotoRenderer {...props} />;
  }
}
      
      



Server Components, :





// PhotoRenderer.server.js - Server Component

import React from 'react';

// one of these will start loading *once rendered and streamed to the client*:
import OldPhotoRenderer from './OldPhotoRenderer.client.js';
import NewPhotoRenderer from './NewPhotoRenderer.client.js';

function Photo(props) {
  // Switch on feature flags, logged in/out, type of content, etc:
  if (FeatureFlags.useNewPhotoRenderer) {
    return <NewPhotoRenderer {...props} />;
  } else {
    return <OldPhotoRenderer {...props} />;
  }
}
      
      



, , .





client-server

- , , , .





. , API. graphql/JSON API .





:





// Note.js
// NOTE: *before* Server Components

function Note(props) {
  const [note, setNote] = useState(null);
  useEffect(() => {
    // NOTE: loads *after* rendering, triggering waterfalls in children
    fetchNote(props.id).then(noteData => {
      setNote(noteData);
    });
  }, [props.id]);
  if (note == null) {
    return "Loading";
  } else {
    return (/* render note here... */);
  }
}
      
      



Note, . server components , :





// Note.server.js - Server Component

function Note(props) {
  // NOTE: loads *during* render, w low-latency data access on the server
  const note = db.notes.get(props.id);
  if (note == null) {
    // handle missing note
  }
  return (/* render note here... */);
}
      
      



したがって、コンポーネントがサーバー上で実行されると、必要なapiと対話し、ユーザーのネットワークを介して1回の反復でデータをコンポーネントに転送できます。その後、コンポーネントの実行結果がユーザーにストリーミングされます。





結果

私の意見では、サーバーコンポーネントには、サスペンス、コンカレントモード、サーバーコンポーネントを組み合わせることで、開発者にとって柔軟性があり、UIを実装するのにユーザーフレンドリーな場所があります。





このRFCとアプローチ、実装、およびAPIは、公式リリースの前に変更される可能性があることを忘れないでください。





サーバーコンポーネントについてどう思いますか?





追加資料

サーバーコンポーネントについて詳しく知りたい場合。





ダン・アブラモフのスピーチ





RFCドキュメント





サンプルアプリケーション








All Articles