いわゆるheader, main, footerとかで構成されるサイトにて、headerやfooterを共通パーツ化したい。
(逆に言えば、headerやfooterはそのままにmainの内容を切り替えたい)
前提
- ルーティングには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直下に置いています)。
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>で行う必要があるようです。
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",
}
}