//tips
//smart contract
取得したapiデータをきれいに表示できるようにMaterial-UIの使い方を確認していく。
npm install @mui/material @mui/styled-engine-sc styled-components
まずはインストール。
調べていくとNext.jsアプリでMaterial-UIを使うときには下記のファイルに変更が必要とのこと。
_app.js
_document.js
_app.jsはnext.authと組み合わせるとややこしいことになりそう。
https://github.com/mui/material-ui/tree/master/examples/nextjs/pages
まずは新たにプロジェクトを作成し、慣れるまでそちらで動かした方が良さそう。
npx create-next-app material-ui-app --use-npm
プロジェクトを作成し、再度MUIをインストール。
_app.jsと_document.jsで読み込むMaterial-UI全体に適用するtheme.jsを作成。
初期のものにMUIを適用。
参考:
https://amateur-engineer-blog.com/how-to-use-material-ui-with-nextjs/
npm install @material-ui/iconsも追加。
調べていくとTypescriptの説明がメインになっている。
npm install @mui/material @emotion/react @emotion/styled
Module not found: Can't resolve '@material-ui/core’のエラーが消えない。
ここからは気合でmuiのサンプルを見ながらゴリゴリ反応を見ていった。1ページのみだったら_app.jsや_document.jsなどの複数ページ対応のものは不要なのでひたすら使いそうな例を当てはめて見てみた。
https://mui.com/components/drawers/
ざっくり作成。
import * as React from 'react';
import Container from '@mui/material/Container';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import { Button } from '@mui/material';
//card
import Card from '@mui/material/Card';
import CardActions from '@mui/material/CardActions';
import CardContent from '@mui/material/CardContent';
//TOPバー
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import IconButton from '@mui/material/IconButton';
//sideバー
import Drawer from '@mui/material/Drawer';
import CssBaseline from '@mui/material/CssBaseline';
import List from '@mui/material/List';
import Divider from '@mui/material/Divider';
import ListItem from '@mui/material/ListItem';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import InboxIcon from '@mui/icons-material/MoveToInbox';
import MailIcon from '@mui/icons-material/Mail';
const drawerWidth = 240;
export default function Index() {
//<Container maxWidth="sm">
return (
<Container>
<Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar
position="fixed"
sx={{ width: `calc(100% - ${drawerWidth}px)`, ml: `${drawerWidth}px` }}
>
<Toolbar>
<Typography variant="h6" noWrap component="div">
Permanent drawer
</Typography>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
'& .MuiDrawer-paper': {
width: drawerWidth,
boxSizing: 'border-box',
},
}}
variant="permanent"
anchor="left"
>
<Toolbar />
<Divider />
<List>
{['Inbox', 'Starred', 'Send email', 'Drafts'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
<Divider />
<List>
{['All mail', 'Trash', 'Spam'].map((text, index) => (
<ListItem button key={text}>
<ListItemIcon>
{index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
</ListItemIcon>
<ListItemText primary={text} />
</ListItem>
))}
</List>
</Drawer>
<Box
component="main"
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3 }}
>
<Toolbar />
<Typography paragraph>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Rhoncus dolor purus non
enim praesent elementum facilisis leo vel. Risus at ultrices mi tempus
</Typography>
<Button variant="contained">Hello World</Button>
<Card sx={{ minWidth: 275 }}>
<CardContent>
<Typography sx={{ fontSize: 14 }} gutterBottom>
Word of the Day
</Typography>
<Typography variant="body2">
well meaning and kindly.
<br />
{'"a benevolent smile"'}
</Typography>
</CardContent>
</Card>
</Box>
</Box>
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
>
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
News
</Typography>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
</Box>
<Box sx={{ my: 4 }}>
<Typography variant="h4" component="h1" gutterBottom>
Next.js example
</Typography>
<>
<Button variant="contained">Hello World</Button>
</>
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<IconButton
size="large"
edge="start"
color="inherit"
aria-label="menu"
sx={{ mr: 2 }}
>
</IconButton>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
News
</Typography>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
</Box>
<Typography variant="h1" component="h2">
h1. Heading
</Typography>
<Card sx={{ minWidth: 275 }}>
<CardContent>
<Typography sx={{ fontSize: 14 }} gutterBottom>
Word of the Day
</Typography>
<Typography variant="h5" component="div">
belent
</Typography>
<Typography sx={{ mb: 1.5 }} >
adjective
</Typography>
<Typography variant="body2">
well meaning and kindly.
<br />
{'"a benevolent smile"'}
</Typography>
</CardContent>
<CardActions>
<Button size="small">Learn More</Button>
</CardActions>
</Card>
</Box>
</Container>
);
}
before-auth-appにカムバック。下記エラーの検証。
{ mymedium.map(({author,title},index) => {
return (
<li key={index}>
{ mymedium.map((item,index) => {
return (
<li key={index}>
<p>{ item.author }</p>
などとして、keyを設定し、コンソールのWarning: Each child in a list should have a unique "key" prop.というエラーを解消しようとしたが別の部分が問題だった。
下記のようにリストを外しても、リストがある形で表示させないとwarningが出るよう。
{statuses && (
<>
{ statuses.map(({ key, id_str,text }) => {
return (
<TwitterTweetEmbed
tweetId={id_str}
/>
これでwarningは解決できるが、不要な・が追加されてしまうのが悩みどころ。map()の解説みたが、liで括る必要があることは書かれていなかったのだが不思議。
{ statuses.map((item,index) => {
return (
<li key={index}>
<TwitterTweetEmbed
tweetId={item.id_str}
/>
</li>
);
})}