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のコーディング

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

  1. import { useNavigate } from "react-router-dom"
  2. import {
  3. BottomNavigation,
  4. BottomNavigationAction,
  5. Toolbar,
  6. Typography
  7. } from "@mui/material";
  8. import HomeIcon from '@mui/icons-material/Home';
  9. import EditIcon from '@mui/icons-material/Edit';
  10. import PageviewIcon from '@mui/icons-material/Pageview';
  11. export default function HeaderNavigation() {
  12. const navigate = useNavigate();
  13. const onClickHome = () => { navigate('/') };
  14. const onClickPage1 = () => { navigate('/page1') };
  15. const onClickPage2 = () => { navigate('/page2') };
  16. return (
  17. <Toolbar sx={{ display: "flex", justifyContent: "space-between" }}>
  18. <Typography component="div" >Markdown</Typography>
  19. <BottomNavigation showLabels>
  20. <BottomNavigationAction label="ホーム" icon={<HomeIcon />} onClick={onClickHome} />
  21. <BottomNavigationAction label="ページ1" icon={<PageviewIcon />} onClick={onClickPage1} />
  22. <BottomNavigationAction label="ページ2" icon={<EditIcon />} onClick={onClickPage2} />
  23. </BottomNavigation>
  24. </Toolbar>
  25. );
  26. }

画面遷移は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のコーディング

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

  1. import { TextField } from "@mui/material"
  2. export default function EditMarkdown(props) {
  3. const { text, onChangeText } = props;
  4. return (
  5. <TextField
  6. id="standard-textarea"
  7. placeholder="# タイトル"
  8. multiline
  9. variant="standard"
  10. value={text}
  11. sx={{ backgroundColor: "#121212", width: "100%", height: "100%", fontSize: "16px", coloc: "white" }}
  12. onChange={onChangeText}
  13. />
  14. );
  15. }

TextFieldをつかいます。

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

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

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

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

全体調整

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

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

HomeTemplateのコーディング

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

  1. import {
  2. AppBar,
  3. Box,
  4. Container,
  5. createTheme,
  6. ThemeProvider,
  7. Toolbar,
  8. } from "@mui/material";
  9. import HeaderNavigation from "../organisms/HeaderNavigation";
  10. export default function HomeTemplate() {
  11. const darkTheme = createTheme({
  12. palette: {
  13. mode: "dark",
  14. primary: {
  15. main: "#1976d2"
  16. }
  17. }
  18. });
  19. return (
  20. <ThemeProvider theme={darkTheme}>
  21. <Box
  22. sx={{
  23. display: "flex",
  24. flexDirection: "column",
  25. height: "100vh"
  26. }}
  27. >
  28. <AppBar position="relative" >
  29. <HeaderNavigation />
  30. </AppBar>
  31. <Box >
  32. <Toolbar sx={{ backgroundColor: "#1976d2" }}>サブヘッダ</Toolbar>
  33. </Box>
  34. <Box component="main" >
  35. <Container maxWidth="xl">
  36. メインページ
  37. </Container >
  38. </Box>
  39. </Box>
  40. </ThemeProvider>
  41. );
  42. }

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

MarkdownTemplateのコーディング

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

  1. import { useState, useEffect } from "react";
  2. import ReactMarkdown from "react-markdown";
  3. import remarkGfm from 'remark-gfm';
  4. import axios from 'axios';
  5. import {
  6. AppBar,
  7. Box,
  8. Container,
  9. createTheme,
  10. CssBaseline,
  11. Drawer,
  12. ThemeProvider,
  13. Toolbar
  14. } from "@mui/material";
  15. import HeaderNavigation from "../organisms/HeaderNavigation";
  16. export default function MarkDownTemplate() {
  17. const darkTheme = createTheme({
  18. palette: {
  19. mode: "dark",
  20. primary: {
  21. main: "#1976d2"
  22. }
  23. }
  24. });
  25. const [text, setText] = useState("");
  26. useEffect(() => {
  27. axios.get('http://localhost:5000/markdown')
  28. .then(res => {
  29. setText(res.data.body)
  30. })
  31. }, [])
  32. return (
  33. <ThemeProvider theme={darkTheme}>
  34. <Box
  35. sx={{
  36. display: "flex",
  37. flexDirection: "column",
  38. height: "100vh"
  39. }}
  40. >
  41. <AppBar position="relative" >
  42. <HeaderNavigation />
  43. </AppBar>
  44. <Box >
  45. <Toolbar sx={{ backgroundColor: "#1976d2" }}>サブヘッダ</Toolbar>
  46. </Box>
  47. <Drawer></Drawer>
  48. <Box component="main" >
  49. <Box
  50. sx={{
  51. display: "flex",
  52. flexDirection: "row"
  53. }}
  54. >
  55. <Container maxWidth="xl">
  56. <ReactMarkdown remarkPlugins={[remarkGfm]} style={{ width: "100%" }}>{text}</ReactMarkdown>
  57. </Container >
  58. </Box>
  59. </Box>
  60. </Box>
  61. </ThemeProvider>
  62. );
  63. }

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

EditTemplateのコーディング

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

  1. import {
  2. AppBar,
  3. Box,
  4. createTheme,
  5. ThemeProvider,
  6. Toolbar,
  7. Container,
  8. Button
  9. } from "@mui/material";
  10. import { useState, useEffect } from "react";
  11. import ReactMarkdown from "react-markdown";
  12. import remarkGfm from 'remark-gfm';
  13. import axios from 'axios';
  14. import HeaderNavigation from "../organisms/HeaderNavigation";
  15. import EditMarkdown from "../organisms/EditMarkdown";
  16. import SaveIcon from '@mui/icons-material/Save';
  17. export default function EditTemplate() {
  18. const darkTheme = createTheme({
  19. palette: {
  20. mode: "dark",
  21. primary: {
  22. main: "#1976d2"
  23. }
  24. }
  25. });
  26. const [text, setText] = useState("");
  27. const onChangeText = (event) => setText(event.target.value);
  28. useEffect(() => {
  29. axios.get('http://localhost:5000/markdown')
  30. .then(res => {
  31. setText(res.data.body)
  32. })
  33. }, [])
  34. const onClickText = () => {
  35. const markdown = {
  36. body: text
  37. };
  38. axios.post(`http://localhost:5000/markdown`, markdown)
  39. .then(res => {
  40. console.log(res.data);
  41. })
  42. };
  43. return (
  44. <ThemeProvider theme={darkTheme}>
  45. <Box
  46. sx={{
  47. display: "flex",
  48. flexDirection: "column",
  49. height: "100vh"
  50. }}
  51. >
  52. <AppBar position="relative" >
  53. <HeaderNavigation />
  54. </AppBar>
  55. <Box >
  56. <Toolbar sx={{ backgroundColor: "#1976d2" }}>サブヘッダ</Toolbar>
  57. </Box>
  58. <Box component="main" >
  59. <Box
  60. sx={{
  61. display: "flex",
  62. flexDirection: "row"
  63. }}
  64. >
  65. <Box
  66. sx={{
  67. height: "100vh",
  68. width: "50%",
  69. backgroundColor: "#121212"
  70. }}
  71. >
  72. <Container >
  73. <Button variant="contained" onClick={onClickText} startIcon={<SaveIcon />}>保存</Button>
  74. <br />
  75. <EditMarkdown text={text} onChangeText={onChangeText} />
  76. </Container >
  77. </Box>
  78. <Box sx={{ width: "50%" }}>
  79. <Container >
  80. <ReactMarkdown remarkPlugins={[remarkGfm]}>{text}</ReactMarkdown>
  81. </Container >
  82. </Box>
  83. </Box>
  84. </Box>
  85. </Box>
  86. </ThemeProvider>
  87. );
  88. }

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

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

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

画面確認

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

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

  1. docker-compose up

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

http://localhost:3000

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

ホームページ

markdown-homepage

ページ1ページ

markdown-page1

ページ2ページ

markdown-page2

まとめ

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

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

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

コメント

0 件のコメント:

コメントを投稿

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