Gatsbyがルートを処理するため、Reduxストアまたはプロバイダーでアプリをラップする場所がありません。 この記事では、それを回避するための巧妙なトリックを学びます。
簡単にするために、すべての例では、状態管理にReactの Context API を使用して、ボイラープレートの設定にかかる時間を節約していますが、他の状態管理方法にもすべて適用できます。 プロバイダーとの連携をブラッシュアップする必要がある場合は、useContextフックのこのイントロを確認できます。
インストール
私は非常に基本的なテーマから始めることを好みますが、最終的には2ページの何かが必要なだけなので、私たちの状態がグローバルに適用されていることがわかります。 いくつかのスタイリングで作業するので、Sassサポートを追加します node-sass
と gatsby-plugin-sass
、私は動物ではないので。
$ gatsby new stateful-gatsby https://github.com/gatsbyjs/gatsby-starter-defaultCopyInstall
$ cd stateful-gatsby
$ yarn add node-sass gatsby-plugin-sass -D
プロバイダーによるラッピング
最初のステップは、シンプルなコンテキストプロバイダーをセットアップすることです isDark
状態とその現在の状態を逆にする方法。 渡されたものはすべて小道具として受け取り、新しいもので包みます myContext.Provider
.
import React, { useState } from 'react';
export const myContext = React.createContext();
const Provider = props => {
const [isDark, setTheme] = useState(false);
return (
<myContext.Provider value={{
isDark,
changeTheme: () => setTheme(!isDark)
}}>
{props.children}
</myContext.Provider>
)
};
そのすぐ下に、新しいプロバイダーで渡されたものをすべてラップする関数をエクスポートします。
export default ({ element }) => (
<Provider>
{element}
</Provider>
);
状態を管理する方法ができたので、ギャツビーは私たちにと呼ばれるきちんとした小さなフックを提供します wrapRootElement
、docsで確認できます。 このフックは、サイトの大部分を取得し、エクスポート元の関数のように、指定した関数に小道具として渡します。 Provider.js
、すべてを中に包むのに最適な小さなスペースを提供してくれます。
両方 gatsby-browser.js
と gatsby-ssr.js
このフックにアクセスでき、両方をプロバイダーでラップすることをお勧めします。そのため、ラッパー関数をで定義しました。 provider.js
.
import Provider from './provider';
export const wrapRootElement = Provider;
スタイリング
シンプルなテーマスタイルは次のとおりです。
.colorTheme
height: 100vh
transition: .3s ease-in-out
.darkTheme
@extend .colorTheme
background-color: #1A202C
color: #fff
a
color: yellow
.lightTheme
@extend .colorTheme
background-color: #fff
color: #000
テーマの適用
状態にアクセスするために必要なのは、各コンポーネントを myContext.Consumer
そして私たちのグローバルな状態にアクセスします context
、 React.Fragment は、複数の要素を追加できるようにするためのものです。
背景色については、条件付きでクラスを状態に設定できます。複数のテーマがある場合は、プロバイダーのテーマをクラス名の文字列として設定できます。
import { myContext } from '../../provider';
import '../global.sass';
return (
<myContext.Consumer>
{context => (
<React.Fragment>
<div className={context.isDark ? 'darkTheme' : 'lightTheme'}>
{/* ... */}
</div>
</React.Fragment>
)}
</myContext.Consumer>
)
また、にアクセスできます setTheme
に渡したので changeTheme
方法。 反転するボタンを追加しましょう isDark
.
import { myContext } from '../../provider';
const IndexPage = () => (
<Layout>
<myContext.Consumer>
{context => (
<React.Fragment>
<SEO title="Home" />
<h1>{context.isDark ? "Dark Theme" : "Light Theme"}</h1>
<button onClick={() => context.changeTheme()}>{context.isDark ? "Light" : "Dark"}</button>
<Link to="/page-2/">Go to page 2</Link>
</React.Fragment>
)}
</myContext.Consumer>
</Layout>
);
ここで、基本的に同じ構成をに追加すると、 page-2.js
状態を変更してそれらの間を移動できるはずですが、状態はそれらの間で一貫しています。
import { myContext } from '../../provider';
const SecondPage = () => (
<Layout>
<myContext.Consumer>
{context => (
<React.Fragment>
<SEO title="Page two" />
<h1>{context.isDark ? "Dark Theme" : "Light Theme"}</h1>
<p>Welcome to page 2</p>
<button onClick={() => context.changeTheme()}>{context.isDark ? "Light" : "Dark"}</button>
<Link to="/">Go back to the homepage</Link>
</React.Fragment>
)}
</myContext.Consumer>
</Layout>
);
フザ! それは本当にそれと同じくらい簡単です。3つの小さなファイルの変更とすべてをコンシューマーでラップするので、準備は完了です。
結論
私にとって、これは物事を行うための非常に明白な方法ではなかったので、これが使用方法を理解するのに役立つことを願っています wrapRootElement
あなたの利点にフックします。
便宜上、この設定をスターターとして使用してリポジトリを作成しました。これは、ここでチェックアウトできます。