Router & MUI
Router & Material UI
2019/07/26 (增加內容)
React Router
基本上,react只會有單一的入口,也就是從index.js開始執行,而且不像php那樣,可以直接執行任何的php檔案。所以,當我們的程式長大之後,就必須要靠router來幫忙了。假如,我們有兩個子功能,一個是StudentApp (詳參: Airtable),另一個是EmployeeApp (詳參: React + Spring Rest),怎麼把這兩個部分放在一起呢?
首先,先安裝react-router套件。
npm install react-router-dom
Router有好幾種,先採用BrowserRouter。BrowserRouter中設定Switch,在Switch中設定Route,利用Route設定哪個路徑會對應到哪個component。Switch的作用是只要第一個path成立就不會往下,這樣會讓速度加快,不過,要注意的是path="/"就不能放在path="/student"之前,否則就不會執行path="/student"了。
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Switch, Route} from 'react-router-dom';
import './index.css';
//import App from './App';
import ReactApp from './components/react-app.js';
import EmployeeApp from './components/employee-app.js';
import StudentApp from './components/student-app.js';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route path="/student" component={StudentApp}/>
<Route path="/employee" component={EmployeeApp}/>
<Route path="/" component={ReactApp}/>
</Switch>
</BrowserRouter>
, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
另一種解決方法是在path="/"前加exact,那就不會把"/"跟"/student"及"/employee"弄混了。
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter, Switch, Route} from 'react-router-dom';
import './index.css';
//import App from './App';
import ReactApp from './components/react-app.js';
import EmployeeApp from './components/employee-app.js';
import StudentApp from './components/student-app.js';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route exact path="/" component={ReactApp}/>
<Route path="/student" component={StudentApp}/>
<Route path="/employee" component={EmployeeApp}/>
</Switch>
</BrowserRouter>
, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();
接下來就可以利用"Link"去連接到這些路徑,其實跟<a> </a>的作用類似,只是Link是client side routing,<a> </a>是server side routing。(詳參: Basic routing in React using React Router 之 Why do we need Link component, why not a HTML anchor tag with href?)
react-app.js
import React from 'react';
//import EmployeeList from './employee-list';
//import EmployeeAdd from './employee-add';
import {Link} from 'react-router-dom';
import { Button } from '@material-ui/core/';
export default function ReactApp() {
return (
<div>
<Button><Link to='/employee'>LINK to employee</Link></Button>
<Button><Link to='/student'>LINK to student</Link></Button>
</div>
)
}
employee-app.js
import React from 'react';
import EmployeeList from './employee-list';
import EmployeeAdd from './employee-add';
import {Link} from 'react-router-dom';
export default function EmployeeApp() {
return (
<div>
<Link to='/'>LINK to student</Link>
<EmployeeAdd/>
<EmployeeList/>
</div>
)
}
student-app.js
import React from 'react';
import {Link} from 'react-router-dom';
import StudentList from './student-list';
import StudentAdd from './student-add';
export default function StudentApp() {
return (
<div>
<Link to='/employee'>LINK to employee</Link>
<StudentAdd/>
<StudentList/>
</div>
)
}
其實設定好router之後,也可以直接用url啟動這兩個app,例如:
http://localhost:3000/student
Material-UI (MUI)
我們來結合Material-UI的AppBar以及router,首先,先新增一個AppBar。
import React from 'react';
import {Link} from 'react-router-dom';
import { AppBar } from '@material-ui/core/';
export default function ReactApp() {
return (
<div>
<AppBar >
<Link to='/employee'>employee</Link>
<Link to='/student'>student</Link>
</AppBar>
</div>
)
}
會發現這兩個連結並不會橫著擺,我們需要加Toolbar。
import React from 'react';
import {Link} from 'react-router-dom';
import { AppBar, Toolbar } from '@material-ui/core/';
export default function ReactApp() {
return (
<div>
<AppBar>
<Toolbar>My App
<Link to='/employee'>employee</Link>
<Link to='/student'>student</Link>
</Toolbar>
</AppBar>
</div>
)
}
要讓Link的style跟著AppBar,就把Link包在Button的component裡,並設定顏色是繼承上一層。
import React from 'react';
import {Link} from 'react-router-dom';
import { AppBar, Toolbar, Button } from '@material-ui/core/';
export default function ReactApp() {
return (
<div>
<AppBar >
<Toolbar>
MyApp
<Button component={Link} to='/student' color="inherit">student</Button>
<Button component={Link} to='/employee' color="inherit">employee</Button>
</Toolbar>
</AppBar>
</div>
)
}
為了讓每一頁都有Menu,也不要讓Menu擋到內容,做了一些調整。
先調整一下styles.js,增加main的style,上面空出menu需要的空間。
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles(theme => ({
root: {
//width: '85%',
marginTop: theme.spacing(3),
marginLeft: theme.spacing(3),
marginRight: theme.spacing(3),
overflowX: 'auto',
},
table: {
minWidth: 650,
},
main: {
paddingTop: theme.spacing(8)
},
}));
export default useStyles;
調整一下react-app.js
import React from 'react';
import MyMenu from './menu';
export default function ReactApp() {
return (
<div>
<MyMenu/>
</div>
)
}
將AppBar的部分獨立為MyMenu (menu.js)
import React from 'react';
import {Link} from 'react-router-dom';
import { AppBar, Toolbar, Button } from '@material-ui/core/';
export default function MyMenu() {
return (
<AppBar >
<Toolbar>
MyApp
<Button component={Link} to='/student' color="inherit">student</Button>
<Button component={Link} to='/employee' color="inherit">employee</Button>
</Toolbar>
</AppBar>
)
}
將MyMenu放到student-app.js,利用Container讓內容往下,避免跟MyMenu重疊。
import React from 'react';
import { Container } from '@material-ui/core/';
import StudentList from './student-list';
import StudentAdd from './student-add';
import MyMenu from './menu';
import useStyles from './styles';
export default function StudentApp() {
const classes = useStyles();
return (
<div>
<MyMenu/>
<Container className={classes.main}>
<StudentAdd/>
<StudentList/>
</Container>
</div>
)
}
將MyMenu放到employee-app.js,利用Container讓內容往下,避免跟MyMenu重疊。
import React from 'react';
import { Container } from '@material-ui/core/';
import EmployeeList from './employee-list';
import EmployeeAdd from './employee-add';
import MyMenu from './menu';
import useStyles from './styles';
export default function EmployeeApp() {
const classes = useStyles();
return (
<div>
<MyMenu/>
<Container className={classes.main}>
<EmployeeAdd/>
<EmployeeList/>
</Container>
</div>
)
}
參考資料
React Router
Basic intro to React Router v4
<BrowserRouter>
<Route>
<Link>
Deep dive into React Router