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

Material-UI