ReactのMUIをつかって部品を作成する

シャープ記号

Reactを勉強するなかで部品化に挑戦しようと思います。

今回はReactのMUIを使った部品作成について紹介します。

前回の内容は以下を参照してください。

ReactのMUIをつかってテンプレート作成

部品化は以下の手順で行います。

ヘッダリンクの部品化

ヘッダリンクを部品化します。

ディレクトリとファイル作成

「src」配下に「organisms」ディレクトリを作成します。

    
project/
  ┗ web/
    ┣ Dockerfile
     ┗ src/
         ┗ react-project/
           ┗ src/
                  ┣ organisms/
                  ┣ pages/
                  ┃ ┣ HomePage.js
                  ┃ ┣ Page1Page.js
                  ┃ ┗ P1ge2Page.js
                  ┣ template/
                  ┃ ┗ HomeTemplate.js
                  ┃ ┗ MarkdownTemplate.js
                  ┃ ┗ EditTemplate.js
                  ┣ component/
                  ┗ App.js
    
  

「organisms」配下に「HeaderNavigation」ファイルをを作成します。

    
project/
  ┗ web/
    ┣ Dockerfile
     ┗ src/
         ┗ react-project/
           ┗ src/
                  ┣ organisms/
                  ┃ ┗ HeaderNavigation.js
                  ┣ pages/
                  ┃ ┣ HomePage.js
                  ┃ ┣ Page1Page.js
                  ┃ ┗ P1ge2Page.js
                  ┣ template/
                  ┃ ┗ HomeTemplate.js
                  ┃ ┗ MarkdownTemplate.js
                  ┃ ┗ EditTemplate.js
                  ┣ component/
                  ┗ App.js
    
  

以上でディレクトリとファイルの作成は終了です。

HeaderNavigationのコーディング

内容は以下のとおりです。

    
import { useNavigate } from "react-router-dom"

import {
  BottomNavigation,
  BottomNavigationAction,
  Toolbar,
  Typography
} from "@mui/material";

import HomeIcon from '@mui/icons-material/Home';
import EditIcon from '@mui/icons-material/Edit';
import PageviewIcon from '@mui/icons-material/Pageview';

export default function HeaderNavigation() {

  const navigate = useNavigate();

  const onClickHome = () => { navigate('/') };
  const onClickPage1 = () => { navigate('/page1') };
  const onClickPage2 = () => { navigate('/page2') };

  return (
    <Toolbar sx={{ display: "flex", justifyContent: "space-between" }}>
      <Typography component="div" >Markdown</Typography>
      <BottomNavigation showLabels>
        <BottomNavigationAction label="ホーム" icon={<HomeIcon />} onClick={onClickHome} />
        <BottomNavigationAction label="ページ1" icon={<PageviewIcon />} onClick={onClickPage1} />
        <BottomNavigationAction label="ページ2" icon={<EditIcon />} onClick={onClickPage2} />
      </BottomNavigation>
    </Toolbar>
  );
}
    
  

画面遷移はLinkタグを使っていましたが、ここではuseNavigateをつかいます。

ボタンはMUIのBottomNavigationとBottomNavigationActionをつかいます。

BottomNavigationについては以下を参照してください。

BottomNavigationActionについては以下を参照してください。

以上がHeaderNavigationのコーディングです。

テキストエリアの部品化

テキストエリアの部品化をします。

ファイル作成

「organisms」配下に「EditMarkdown」ファイルをを作成します。

    
project/
  ┗ web/
    ┣ Dockerfile
     ┗ src/
         ┗ react-project/
           ┗ src/
                  ┣ organisms/
                  ┃ ┣ HeaderNavigation.js
                  ┃ ┗ EditMarkdown.js        
                  ┣ pages/
                  ┃ ┣ HomePage.js
                  ┃ ┣ Page1Page.js
                  ┃ ┗ P1ge2Page.js
                  ┣ template/
                  ┃ ┗ HomeTemplate.js
                  ┃ ┗ MarkdownTemplate.js
                  ┃ ┗ EditTemplate.js
                  ┣ component/
                  ┗ App.js
    
  

EditMarkdownのコーディング

内容は以下のとおりです。

    
import { TextField } from "@mui/material"

export default function EditMarkdown(props) {

  const { text, onChangeText } = props;
  return (
      <TextField
        id="standard-textarea"
        placeholder="# タイトル"
        multiline
        variant="standard"
        value={text}
        sx={{ backgroundColor: "#121212", width: "100%", height: "100%", fontSize: "16px", coloc: "white" }}
        onChange={onChangeText}
      />
  );
}
    
  

TextFieldをつかいます。

TextFieldについては以下を参照してください。

multilineを有効にします。有効にすることで複数行の入力が可能です。

この部品は、porpsで、textとonChangeTextを上位の部品から取得します。

以上がEditMarkdownのコーディングです。

全体調整

最後に全体的な調整をします。

修正ファイルは、tempate配下のファイルです。

HomeTemplateのコーディング

HomeTemplateのコーディングは以下のとおりです。

    
import {
  AppBar,
  Box,
  Container,
  createTheme,
  ThemeProvider,
  Toolbar,
} from "@mui/material";

import HeaderNavigation from "../organisms/HeaderNavigation";

export default function HomeTemplate() {
  const darkTheme = createTheme({
    palette: {
      mode: "dark",
      primary: {
        main: "#1976d2"
      }
    }
  });

  return (
    <ThemeProvider theme={darkTheme}>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
          height: "100vh"
        }}
      >
        <AppBar position="relative" >
          <HeaderNavigation />
        </AppBar>
        <Box >
          <Toolbar sx={{ backgroundColor: "#1976d2" }}>サブヘッダ</Toolbar>
        </Box>
        <Box component="main" >
          <Container maxWidth="xl">
            メインページ
          </Container >
        </Box>
      </Box>
    </ThemeProvider>
  );
}
    
  

AppBarタグの配下にLinkタグを記述していましたが、AppBarタグの配下のHeaderNavigationの中に記述します。

MarkdownTemplateのコーディング

MarkdownTemplateのコーディングは以下のとおりです。

    
import { useState, useEffect } from "react";

import ReactMarkdown from "react-markdown";
import remarkGfm from 'remark-gfm';

import axios from 'axios';

import {
  AppBar,
  Box,
  Container,
  createTheme,
  CssBaseline,
  Drawer,
  ThemeProvider,
  Toolbar
} from "@mui/material";

import HeaderNavigation from "../organisms/HeaderNavigation";

export default function MarkDownTemplate() {
  const darkTheme = createTheme({
    palette: {
      mode: "dark",
      primary: {
        main: "#1976d2"
      }
    }
  });

  const [text, setText] = useState("");

  useEffect(() => {
    axios.get('http://localhost:5000/markdown')
      .then(res => {
        setText(res.data.body)
      })
  }, [])

  return (
    <ThemeProvider theme={darkTheme}>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
          height: "100vh"
        }}
      >
        <AppBar position="relative" >
          <HeaderNavigation />
        </AppBar>
        <Box >
          <Toolbar sx={{ backgroundColor: "#1976d2" }}>サブヘッダ</Toolbar>
        </Box>
        <Drawer></Drawer>
        <Box component="main" >
          <Box
            sx={{
              display: "flex",
              flexDirection: "row"
            }}
          >
            <Container maxWidth="xl">
              <ReactMarkdown remarkPlugins={[remarkGfm]} style={{ width: "100%" }}>{text}</ReactMarkdown>
            </Container >
          </Box>
        </Box>
      </Box>
    </ThemeProvider>
  );
}
    
  

こちらもAppBarタグの配下にLinkタグを記述していましたが、AppBarタグの配下のHeaderNavigationの中に記述します。代わりにHeaderNavigationのタグを配置します。

EditTemplateのコーディング

EditTemplateのコーディングは以下のとおりです。

    
import {
  AppBar,
  Box,
  createTheme,
  ThemeProvider,
  Toolbar,
  Container,
  Button
} from "@mui/material";

import { useState, useEffect } from "react";

import ReactMarkdown from "react-markdown";
import remarkGfm from 'remark-gfm';
import axios from 'axios';
import HeaderNavigation from "../organisms/HeaderNavigation";
import EditMarkdown from "../organisms/EditMarkdown";

import SaveIcon from '@mui/icons-material/Save';

export default function EditTemplate() {
  const darkTheme = createTheme({
    palette: {
      mode: "dark",
      primary: {
        main: "#1976d2"
      }
    }
  });

  const [text, setText] = useState("");

  const onChangeText = (event) => setText(event.target.value);

  useEffect(() => {
    axios.get('http://localhost:5000/markdown')
      .then(res => {
        setText(res.data.body)
      })
  }, [])

  const onClickText = () => {
    const markdown = {
      body: text
    };
    axios.post(`http://localhost:5000/markdown`, markdown)
      .then(res => {
        console.log(res.data);
      })
  };


  return (
    <ThemeProvider theme={darkTheme}>
      <Box
        sx={{
          display: "flex",
          flexDirection: "column",
          height: "100vh"
        }}
      >
        <AppBar position="relative" >
          <HeaderNavigation />
        </AppBar>
        <Box >
          <Toolbar sx={{ backgroundColor: "#1976d2" }}>サブヘッダ</Toolbar>
        </Box>
        <Box component="main" >
          <Box
            sx={{
              display: "flex",
              flexDirection: "row"
            }}
          >
            <Box
              sx={{
                height: "100vh",
                width: "50%",
                backgroundColor: "#121212"
              }}
            >
              <Container >
              <Button variant="contained" onClick={onClickText} startIcon={<SaveIcon />}>保存</Button>
                <br />
                <EditMarkdown text={text} onChangeText={onChangeText} />
              </Container >
            </Box>

            <Box sx={{ width: "50%" }}>
              <Container >
                <ReactMarkdown remarkPlugins={[remarkGfm]}>{text}</ReactMarkdown>
              </Container >
            </Box>
          </Box>
        </Box>
      </Box>
    </ThemeProvider>
  );
}
    
  

こちらもAppBarタグの配下にLinkタグを記述していましたが、AppBarタグの配下のHeaderNavigationの中に記述します。代わりにHeaderNavigationのタグを配置します。

部品化することで、各テンプレートで同じコンポーネントを利用することができます。

自作のEditMarkdownタグを追加しました。このタグには、textとonChangeTextを引数で渡します。

画面確認

docker-compose upを使って各コンテナを起動します。

docker-compose.ymlファイルがある場所で以下のコマンドを実行します。

    
docker-compose up
    
  

起動したら以下のURLをブラウザに入力します。

http://localhost:3000

以下ブラウザの表示です。

ホームページ

markdown-homepage

ページ1ページ

markdown-page1

ページ2ページ

markdown-page2

まとめ

Reactを勉強するなかで部品化に挑戦しました。

部品化は難しく何を部品にすればいいのか、いまだにわかりません。

最近Atomic Designを知りました。今後このデザインに沿って部品化を検討する予定です。

コメント

0 件のコメント:

コメントを投稿

コメントをお待ちしています。