ReactアプリケーションサーバーでCSSをレンダリングする方法
序章
Next.js (React)および Nuxt.js (Vue)は、アプリビューをサーバーにレンダリングするプロセスを合理化するのに役立ちます。
開発に対応する方法でReactコンポーネントにCSSをレンダリングするためのソリューションが引き続き必要です。 また、スタイルを使用できるように、サーバーでCSSをレンダリングするためのソリューションも必要になります。
この記事では、CSSのレンダリングの課題について説明し、Next.jsプロジェクトのサーバーでstyled-components
とstyled-jsx
を使用します。
前提条件
このチュートリアルを完了するには、次のものが必要です。
- Node.jsのローカル開発環境。 Node.jsをインストールしてローカル開発環境を作成する方法に従ってください。
このチュートリアルは、ノードv16.2.0、npm
v7.14.0、react
v17.0.2、react-dom
v17.0.2、next
v10.2.3、およびstyled-compnents
v5.3.0。
Reactのスタイルパターンを理解する
ReactでCSSを作成する一般的な方法はいくつかありますが、すべて機能します。 状況に応じて、次のいずれかの方法でReactアプリにスタイルを適用します。
グローバルスタイル
グローバルスタイルは、ローカルまたはコンテンツ配信ネットワーク(CDN)でホストされるスタイルシートを含めるパターンです。
次に例を示します。
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" />
これは、コンポーネントの再利用を促進しないため、あまり好ましくないスタイリングパターンです。 また、スタイルの構成を奨励しません。
これらのCSSルールは、特定の要素またはコンポーネントに直接スコープされていません。 コンポーネントがインポート、ネスト、または拡張によって予期されていなかった方法で相互作用する場合、競合が発生する可能性が高くなります。
ただし、フォントの組み込みやCSSのリセットやデフォルトなど、スタイルをグローバルに含めることができる場合があります。
インラインスタイル
インラインスタイルは、React style
プロパティを使用して、DOM要素またはReactコンポーネントに直接適用されます。 実装はHTMLインラインstyle
属性によく似ていますが、JavaScript element.style
APIを使用します。
次に例を示します。
const titleStyle = { fontSize: '4rem'; lineHeight: '1.6'; color: '#222'; } <h1 style={titleStyle} {...props}>{props.children}<h1>
このパターンは、スタイルとコンポーネントの構成、および再利用を促進します。
ただし、インラインスタイルでは、疑似クラスとターゲット疑似要素を使用してフォーカス状態のホバーを処理する方法は提供されません。 大規模で複雑なプロジェクトの場合、より堅牢なソリューションが必要になる場合があります。
コンポーネントスタイル
コンポーネントスタイルは、再利用を促進し、スタイルとコンポーネントをより適切に構成するのに役立ちます。 これを実現するには、ユーティリティまたはライブラリが必要です。 スタイルローダー、スタイルコンポーネント、グラマーなど。 コンポーネントスタイルをサポートするためのツールの例です。
styled-components
は、CSS-in-JSを実装するための一般的なソリューションです。 これらはインラインコンポーネントスタイルですが、複雑な(疑似)選択、ネストなどを実行するためのより強力な機能を備えています。
ステップ1-プロジェクトの設定
開始するには、ターミナルを開き、プロジェクト用の新しいフォルダを作成します。
mkdir css-ssr-next-example
次に、新しいプロジェクトディレクトリに移動します。
cd css-ssr-next-example
次に、次のコマンドを実行して初期化します。
npm init -y
これにより、依存関係の追跡に使用するpackage.json
ファイルが作成されます。
次に、Next.js、React、およびReactDOMをインストールします。
npm install [email protected] [email protected] react-dom17.0.2
この時点で、Next.js、React、およびReactDOMを使用した新しいプロジェクトが作成されます。
注:公開以来、Next.jsプロジェクトを作成するためのより最新のアプローチでは、create-next-appを利用できます。
次に、package.json
を更新して、dev
スクリプトでNext.jsアプリを起動します。
package.json
{ "name": "css-ssr-next-example", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "next" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "next": "^10.2.3", "react": "^17.0.2", "react-dom": "^17.0.2" } }
次に、pages
ディレクトリを作成します。
mkdir pages
このディレクトリに、次の内容のindex.js
ファイルを追加します。
pages / index.js
import React from 'react'; const Index = () => <h1>Hi, new Next.js project</h1>; export default Index;
次に、dev
スクリプトを実行して、サーバーを起動します。
npm run dev
Webブラウザでlocalhost:3000
を開くと、次のことがわかります。
OutputHi, new Next.js project
まず、NextのHead
コンポーネントを使用して、normalize.css
を使用してスタイルを正規化します。
pages / index.js
import React from 'react'; import Head from 'next/head'; const Index = () => <div> <Head> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" /> <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" /> </Head> <h1>Hi, new Next.js project</h1> </div>; export default Index;
次に、Next.jsプロジェクトのルートにstatic
フォルダーを作成します。
mkdir static
このディレクトリに、次のCSSコンテンツを含むbase.css
ファイルを追加します。
static / base.css
body { font-family: 'Raleway', sans-serif; color: #222; }
base.css
ファイルをインデックスページにインポートします。
pages / index.js
// ... <Head> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.css" /> <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet" /> <link rel="stylesheet" href="/static/base.css" /> </Head> // ...
ブラウザでは、フォントがデフォルトのフォントからRalewayに表示されます。
この時点で、グローバルスタイルのNext.jsプロジェクトができました。
ステップ2–スタイル付きコンポーネントの使用
styled-components
ライブラリを使用してコンポーネントのスタイルを設定しましょう。
まず、styled-components
をインストールします。
npm install [email protected]
次に、components
ディレクトリを作成します。
mkdir components
このディレクトリに、Button.js
ファイルを追加し、次のようにファイルを更新します。
components / Button.js
import React from 'react'; import styled from 'styled-components'; const ButtonBase = (props) => <button {...props}>{props.children}</button> const Button = styled(ButtonBase)` /* Rectangle 2: */ background: #0077E2; box-shadow: 0 2px 7px 0 rgba(120,137,149,0.25); border-radius: 3px; text-transform: uppercase; padding: 10px; color: #fff; border: #0077E2; ` export default Button;
styled
としてインポートされたstyled-components
を使用して、Button
のスタイルを設定しています。 ButtonBase
はボタンのスケルトンを返し、Button
はスタイルが設定されたButtonBase
のコンポーネントを返します。
インデックスページのButton
コンポーネントをインポートして使用します。
index.js
import React from 'react'; import Head from 'next/head'; import Button from '../components/Button' const Index = () => <div> <Head> .... </Head> <h1>Hi, new Next.js project</h1> <Button>Clicker</Button> </div>; export default Index;
変更を保存し、ブラウザでアプリケーションを観察します。 テキストの下には、新しいスタイルのボタンがあります。
ただし、ハードリフレッシュ後、ボタンのスタイルは期待どおりになりません。
ボタンのスタイルが欠落しているように見えますが、どういうわけか、基本のスタイルはそのままです。 Web開発ツールを使用して、ページソースを検査します。
コンテンツはサーバーにレンダリングされますが、ボタンに関連するページのどこにもスタイルは表示されません。 一方、適用されたフォントスタイルからわかるように、外部ファイルがサーバーに正常にレンダリングされたことがわかります。
では、コンポーネントスタイルの何が問題になっているのでしょうか。 コンソールを見てください:
OutputWarning: Prop `className` did not match. Server: "sc-gtsrHT kbmjhF" Client: "sc-bdnxRM kbyRfM"
クラス名の不一致を示すエラーが表示される場合があります。 これは、リロードすると、コンテンツが最初にサーバーからフェッチされるためです。
残念ながら、styled-components
はサーバーにレンダリングされないため、その時点では使用できません。
解決策を見てみましょう。
ステップ3–スタイル付きJSXの使用
Next.jsに取り組んでいるチームは、この問題を軽減するために、styled-jsxというライブラリを導入しました。 ライブラリは、作成したスタイルが、ブラウザだけでなく、サーバーとブラウザでレンダリングされることを保証します。
すでにNext.jsにバンドルされているので、何もインストールする必要はありません。
Button
コンポーネントに再度アクセスし、styled-jsx
を使用するように変更します。
components / Button.js
import React from 'react'; const Button = props => ( <button {...props}> {props.children} <style jsx>{` background: #0077e2; box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25); border-radius: 3px; text-transform: uppercase; padding: 10px; color: #fff; border: #0077e2; `}</style> </button> ); export default Button;
スタイリングするコンポーネントのルート要素の終了タグの前に、jsx
属性を使用してstyle
要素を作成できます。 style
要素で、テンプレート文字列を含む中括弧を開きます。 文字列は有効なCSSスタイルであり、コンポーネントスタイルとしてサーバーである必要があります。
コンポーネントが1つの要素のみで構成されていない場合は、styled-jsx
でセレクターを使用することもできます。
components / TitleAndButton.js
import React from 'react'; const TitleAndButton = props => (<div {...props}> <h1 className="title">Hi Title</h1> <button>Clicker</button> <style jsx>{` h1.title { color: #222 } button { background: #0077e2; box-shadow: 0 2px 7px 0 rgba(120, 137, 149, 0.25); border-radius: 3px; text-transform: uppercase; padding: 10px; color: #fff; border: #0077e2; } `}</style> </div>); export default TitleAndButton;
これで、[インデックス]ページのTitleAndButton
コンポーネントをインポートして使用できます。 両方の要素が期待どおりにスタイル設定されます。
注:Next.jsのwith-styled-jsxの例も参照できます。
styled-jsx
は、Next.jsプロジェクトでサーバーにスタイルをレンダリングするための1つのアプローチです。
結論
この記事では、CSSのレンダリングの課題について学び、Next.jsプロジェクトのサーバーでstyled-components
とstyled-jsx
を使用しました。
Next.jsについて詳しく知りたい場合は、 Next.js入門テクニカルトークを試すか、Next.jsトピックページで演習とプログラミングプロジェクトを確認してください。 。