Material-UI

使用模組為React設計版面

2019/07/21

React + Material-UI(Tables)

這次接續使用上一章的範例 (教學: React - Rest Example),我們直接使用rest讀取的資料來建立一個table,示範如何用Material-UI的「Tables 」模組將資料顯示在頁面上。Material Design是Google開發的設計語言,Material-UI就是一些Material Design的react模組/元件。

事前準備




  • index.js

修改掛載頁面為<PersonList />







  • PersonList.js

讀取API資料複製到 state ( persons )

*添加 console.log() 函數可以在頁面後台看到從接受API接收到的data內容。







  • Browser ( localhost:3000 )

打開瀏覽器查看頁面結果

*右邊為Chrome的開發人員工具,在console標籤可以看到我們剛才log的data內容。


Install Material-UI

Material-UI的官網有安裝指令,我們直接使用npm指令安裝 :

// 用npm安装
npm install @material-ui/core

Table Component

官網的左側導覽列中,點擊Components裡的裡的Tables項目。這裡有很多種功能的表格類型,我們先從最簡單的Simple Table 做練習。

範例上方的按鍵打開可以看見範例代碼:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles(theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing(3),
    overflowX: 'auto',
  },
  table: {
    minWidth: 650,
  },
}));

function createData(name, calories, fat, carbs, protein) {
  return { name, calories, fat, carbs, protein };
}

const rows = [
  createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
  createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
  createData('Eclair', 262, 16.0, 24, 6.0),
  createData('Cupcake', 305, 3.7, 67, 4.3),
  createData('Gingerbread', 356, 16.0, 49, 3.9),
];

function SimpleTable() {
  const classes = useStyles();

  return (
    <Paper className={classes.root}>
      <Table className={classes.table}>
        <TableHead>
          <TableRow>
            <TableCell>Dessert (100g serving)</TableCell>
            <TableCell align="right">Calories</TableCell>
            <TableCell align="right">Fat&nbsp;(g)</TableCell>
            <TableCell align="right">Carbs&nbsp;(g)</TableCell>
            <TableCell align="right">Protein&nbsp;(g)</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map(row => (
            <TableRow key={row.name}>
              <TableCell component="th" scope="row">
                {row.name}
              </TableCell>
              <TableCell align="right">{row.calories}</TableCell>
              <TableCell align="right">{row.fat}</TableCell>
              <TableCell align="right">{row.carbs}</TableCell>
              <TableCell align="right">{row.protein}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </Paper>
  );
}

export default SimpleTable;

import

最上面的部分import所需使用的模組

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

makeStyles()

Material-UI用來定義頁面樣式的hook函式。

const useStyles = makeStyles(theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing(3),
    overflowX: 'auto',
  },
  table: {
    minWidth: 650,
  },
}));

React 特別之處就在於它可以全部使用JavaScript去撰寫網頁,包含html、CSS 跟 Script(雖然這部分本來就是用JS寫的啦哈哈哈)的部分,我們可以統一使用JS定義完成。這種使用JS定義CSS的方法稱為——「 CSS in JS 」(JSS)

當然我們也可以透過import CSS檔,用傳統的方式撰寫網頁樣式,但如果使用了Material-UI,還是建議使用JSS的方式定義樣式,即便要將所有樣式集中到同一個檔案裡管理,也還是可以使用JSS的方式定義樣式。

另外,JSS要特別注意的地方是,由於JS用Object的概念定義樣式,所以有些地方的格式跟CSS不太一樣:

  1. 樣式名稱不用 ' - ' 符號連結而是駝峰式命名。例:overflowX: 'auto',原本在CSS中是 over-flow 的寫法,這裡把連結符號刪掉,第二個單字的第一個字母大寫,變成 overFlow
  2. 樣式的內容為需為變數或字串。例:width: '100%',原本在CSS 100%的數值需要加上' ' 或 " "(JS中兩著皆可);如數值不加單位例:minWidth: 650,預設單位則為 px,即 min-width 等於 650px。
  3. 樣式換行結尾使用 ' , '符號。與一般CSS用分號不同,JSS用的是逗號。

createData()

創建文件資料。這部分不會使用於此次範例中。

function createData(name, calories, fat, carbs, protein) {
  return { name, calories, fat, carbs, protein };
}

const rows = [
  createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
  createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
  createData('Eclair', 262, 16.0, 24, 6.0),
  createData('Cupcake', 305, 3.7, 67, 4.3),
  createData('Gingerbread', 356, 16.0, 49, 3.9),
];

Function Component(SimpleTable())

輸出組件頁面與嵌入資料陣列。

function SimpleTable() {
  const classes = useStyles();

  return (
    <Paper className={classes.root}>
      <Table className={classes.table}>
        <TableHead>
          <TableRow>
            <TableCell>Dessert (100g serving)</TableCell>
            <TableCell align="right">Calories</TableCell>
            <TableCell align="right">Fat&nbsp;(g)</TableCell>
            <TableCell align="right">Carbs&nbsp;(g)</TableCell>
            <TableCell align="right">Protein&nbsp;(g)</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map(row => (
            <TableRow key={row.name}>
              <TableCell component="th" scope="row">
                {row.name}
              </TableCell>
              <TableCell align="right">{row.calories}</TableCell>
              <TableCell align="right">{row.fat}</TableCell>
              <TableCell align="right">{row.carbs}</TableCell>
              <TableCell align="right">{row.protein}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </Paper>
  );
}

export default SimpleTable;

加入Material-UI改寫範例檔案:

export default function PersonList() {

    /*------------ STATE ------------*/
    const [persons, setPersons] = useState([]);

    /*------------ STYLE ------------*/
    const classes = useStyles();

    /*=========== Create Table HEAD ===========*/
    const personList = [ 'id', 'name', 'phone', 'username' ]

    useEffect(() => {
        async function fetchData() {
            const result = await axios.get(`https://jsonplaceholder.typicode.com/users/`);
            setPersons(result.data);
            console.log(result.data)
        }
        fetchData();
    }, []);

    return (
        <Paper className={classes.root}>
            <Table className={classes.table}>

                {/*===== TableHead =====*/}
                <TableHead>
                    <TableRow>
                        {
                            personList.map( (list, i) => i === 0 ?
                                <TableCell key={i} align="center"> {list} </TableCell> :
                                <TableCell key={i} align="right"> {list} </TableCell>
                            ) 
                        }
                    </TableRow>
                </TableHead>

                {/*===== TableBody =====*/}
                <TableBody>
                    {persons.map(person => (
                        <TableRow key={person.name}>
                        {
                            personList.map( (list, i) =>   i === 0 ? 
                                <TableCell key={i} component="th" scope="row" align="center" >
                                   {person[list]}
                                </TableCell>:
                                <TableCell key={i} align="right">{person[list]}</TableCell> 
                            )
                        }
                        </TableRow>
                    ))}
                </TableBody>

            </Table>
        </Paper>
    )
}

改寫後完成頁面:

**感謝伍庭儀同學提供本頁面內容