Help us understand the problem. What is going on with this article?

Reactで表示内容(headerとかfooterとか)のパーツ化・共通化

いわゆるheader, main, footerとかで構成されるサイトにて、headerやfooterを共通パーツ化したい。
(逆に言えば、headerやfooterはそのままにmainの内容を切り替えたい)

スクリーンショット 2019-12-12 10.53.53.png

前提

  • ルーティングにはreact-router-domを利用する
  • よくcore-ui(React)を利用するので、そこでのやり方を踏襲

実装:基本編

App.js

App.jsですべてのルーティングを設定せず、レイアウトや認証が異なるといったレベルでルーティングを設定する。
基本的にDefaultコンポーネントに流す。

import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';

//screens
import Default from './screens/Default';
import Login from './screens/Login';

class App extends React.Component {
    render() {
        return (
            <BrowserRouter>
                <Switch>
                    <Route exact path="/login" component={Login} />
                    <Route path="/" component={Default} />
                </Switch>
            </BrowserRouter>
        );
    }
}

export default App;

Default.js

Default.jsにて基本レイアウトを適用し、変更される部分(ここではmain)をSwitchで囲み、ルーティングを設定する。

import React from 'react';
import { Switch, Route } from 'react-router-dom';

//screens
import Home from './Home';
import About from './About';
import Service from './Service';

class Default extends React.Component {
    render() {
        return (
            <div>
                <header style={styles.header}>head</header>
                <main style={styles.main}>
                    <Switch>
                        <Route exact path="/" component={Home} />
                        <Route path="/about" component={About} />
                        <Route path="/service" component={Service} />
                        <Route render={() => <p>not found!.</p>} />
                    </Switch>
                </main>
                <footer style={styles.footer}>footer</footer>
            </div>
        );
    }
}

export default Default;

//css
const styles = {
    header: {
        height: 100,
        background: "#ddd",
    },
    main: {
        height: 200,
    },
    footer: {
        height: 100,
        background: "#ddd",
    }
}

あとはそれぞれのページのレイアウトを行うだけ。

Home.js

Homeの内容。Homeと表示、リンクを設定してるだけ。

import React from 'react';
import { Link } from 'react-router-dom';

class Home extends React.Component {
    render() {
        return (
            <div>
                <p>Home</p>
                <p><Link to="/">Home</Link></p>
                <p><Link to="/about">About</Link></p>
                <p><Link to="/service">Service</Link></p>
            </div>
        );
    }
}

export default Home;

About.js

基本Homeと同じですが、一応。

import React from 'react';
import { Link } from 'react-router-dom';

class About extends React.Component {
    render() {
        return (
            <div>
                <p>About</p>
                <p><Link to="/">Home</Link></p>
                <p><Link to="/about">About</Link></p>
                <p><Link to="/service">Service</Link></p>
            </div>
        );
    }
}

export default About;

Service.js

基本Homeと同じですが、一応。

import React from 'react';
import { Link } from 'react-router-dom';

class Service extends React.Component {
    render() {
        return (
            <div>
                <p>Service</p>
                <p><Link to="/">Home</Link></p>
                <p><Link to="/about">About</Link></p>
                <p><Link to="/service">Service</Link></p>
            </div>
        );
    }
}

export default Service;

実装:応用編

コンポーネントが大量になると記述も大変だし、何より読み込みに時間がかかる。
core-uiのソースを見てるとroutesを変数化し、なおかつlazy()リードしている。

routes.js

まず、読み込みやルートの定義は別ファイル化して下記のように記述します(場所はとりあえずsrc直下に置いています)。

routes.js
import React from 'react';

const Home = React.lazy(() => import('./screens/Home'));
const About = React.lazy(() => import('./screens/About'));
const Service = React.lazy(() => import('./screens/Service'));

const routes = [
    { path: '/', exact: true, name: 'Home', component: Home },
    { path: '/about', exact: true, name: 'About', component: About },
    { path: '/service', exact: true, name: 'Service', component: Service },
]

export default routes;

Home.js

Home.js等でroutes.jsをimportし、ループにてRouteを設定しています。
なお、lazy()を使うと、読み込みの間表示するコンテンツの指定を<Suspense></Suspence>で行う必要があるようです。

Default.js
import React, { Suspense } from 'react';
import { Switch, Route } from 'react-router-dom';

import routes from '../routes';

class Default extends React.Component {

    loading = () => <div>Loading...</div>

    render() {
        return (
            <div>
                <header style={styles.header}>head</header>
                <main style={styles.main}>
                    <Suspense fallback={this.loading}>
                        <Switch>
                            {
                                routes.map((route, index) => (
                                    <Route
                                        key={index}
                                        path={route.path}
                                        exact={route.exact}
                                        name={route.name}
                                        render={props => (<route.component {...props} />)}
                                    />
                                ))
                            }
                            <Route render={() => <p>not found!.</p>} />
                        </Switch>
                    </Suspense>
                </main>
                <footer style={styles.footer}>footer</footer>
            </div>
        );
    }
}

export default Default;

const styles = {
    header: {
        height: 100,
        background: "#ddd",
    },
    main: {
        height: 200,
    },
    footer: {
        height: 100,
        background: "#ddd",
    }
}
zaburo
こんにちは。自分用のメモをだらだら公開しています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした