【React】簡単なお問い合わせフォームの実装|ポートフォリオサイトの作り方

作成日: 更新日:

開発環境

  • Visual Studio Code:version 1.73.0
  • OS:Windows10
  • Node.js:v18.14.0
  • npm:9.3.1
  • react:18.2.0
  • react-dom:18.2.0
  • react-router-dom:6.8.2
  • typescript:4.9.5
  • mui:5.11.10
  • mui/icons-material:5.11.11
  • chart.js:4.4.0
  • react-chartjs-2:5.2.0

Reactでお問い合わせフォームを実装する手順

Reactでお問い合わせフォームを実装する手順を解説します。

コンタクトフォームコンポーネントを作成する

まずはコンタクトフォームコンポーネントを作成します。

1// src/components/ContactForm.tsx
2import React, { useState } from "react";
3import Box from "@mui/material/Box";
4import Grid from "@mui/material/Grid";
5import Typography from "@mui/material/Typography";
6import Button from "@mui/material/Button";
7import Stack from "@mui/material/Stack";
8import TextField from "@mui/material/TextField";
9import CircularProgress from "@mui/material/CircularProgress";
10
11const ContactForm: React.FC = () => {
12    const [email, setEmail] = useState('');
13    const [message, setMessage] = useState('');
14    const [emailSent, setEmailSent] = useState(false);
15    const [isSending, setIsSending] = useState(false);
16
17    const sleep = (waitTime: number) => new Promise( resolve => setTimeout(resolve, waitTime));
18
19    const handleEmailchange = (event: React.ChangeEvent<HTMLInputElement>) => {
20        setEmail(event.target.value);
21    };
22
23    const handleMessagechange = (event: React.ChangeEvent<HTMLInputElement>) => {
24        setMessage(event.target.value);
25    };
26
27    const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
28        event.preventDefault();
29
30        try {
31            setIsSending(true);
32            // 送信する処理
33            await sleep(5000);
34            console.log("メールが送信されました。")
35            // メール送信が終わったあと
36            setEmailSent(true);
37        } catch (error) {
38            console.log(error);
39        } finally {
40            setIsSending(false);
41        };
42        console.log('送信されたメール:', email)
43        console.log('送信されたメッセージ:', message)
44    };
45
46    return(
47        <>
48            <Grid container rowSpacing={2} columnSpacing={2}>
49                <Grid item xs={12} md={12} sx={{ textAlign: 'center' }}>
50                    <Typography component="h2" variant="h2">
51                        Contact
52                    </Typography>
53                </Grid>
54                <Grid item xs={12} md={12}>
55                    {emailSent ? (
56                        <Box sx={{ width: "100%", textAlign: "center" }}>
57                            メールが送信されました。
58                        </Box>
59                    ) : (
60                        <Stack sx={{ width: "100%" }} component="form" spacing={2} onSubmit={handleSubmit} autoComplete="off">
61                            <TextField required fullWidth label="メールアドレス" name="email" variant="outlined" value={email} onChange={handleEmailchange} />
62                            <TextField required fullWidth multiline rows={4} label="お問い合わせ内容" name="message" variant="outlined" value={message} onChange={handleMessagechange} />
63                            {isSending ? (
64                                <Button variant="contained" color="primary">
65                                    <CircularProgress />
66                                </Button>
67                            ) : (
68                                <Button type="submit" variant="contained" color="primary">
69                                    送信
70                                </Button>
71                            )}
72                        </Stack>
73                    )}
74                </Grid>
75            </Grid>
76        </>
77    );
78};
79
80export default ContactForm;

疑似的にメール送信中であることを表現するために16行目でsleep関数を定義し、32行目で5秒待機するようにしています。 ポイントは18行目の「handleEmailchange」でEmailの入力状況をStateで状態管理、22行目の「handleMessagechange」でメッセージの入力状況をStateで状態管理しています。 あとはSubmitが推された場合に「handleSubmit」が呼び出されてメールを送信する処理が実行されますが、submitイベントの発生元であるフォームが持つデフォルトの動作をキャンセルするために「event.preventDefault();」を忘れないようにしましょう。 また、12行目の「emailSent」はメールの送信結果、13行目の「isSending」はメールの送信中であるかを状態管理しています。 その結果によって54行目以降のお問い合わせフォームの表示を切り替えられるようにしています。

トップページコンポーネントを修正する

最後にトップページコンポーネントを修正します。

1// src/pages/homes/top.tsx
2
3import MV from "../../assets/images/mv.jpg"
4import SkillList from "../../components/SkillList"
5import ProductionList from "../../components/ProductionList"
6import ProfileList from "../../components/ProfileList";
7+ import ContactForm from "../../components/ContactForm";
8
9const Top: React.FC = () => {
10    return(
11        <>
12            <Box sx={{ height: "65vh", backgroundImage: "url(" + MV + ")", backgroundSize: "cover", backgroundPosition: "center", position: "relative" }}>
13                <Container maxWidth='md' sx={{ position: "absolute", top: "30%", left: "50%", transform: "translateX(-50%) translateY(-50%)" }}>
14                    <Grid container rowSpacing={2} columnSpacing={2} sx={{ textAlign: "center",color: "#FFFFFF", textShadow: "1px 1px 3px #000000" }}>
15                        <Grid item xs={12} md={12}>
16                            <Typography component="h2" variant="h2">
17                                MVタイトル
18                            </Typography>
19                        </Grid>
20                        <Grid item xs={12} md={12}>
21                            <Typography>
22                                テキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト
23                            </Typography>
24                        </Grid>
25                    </Grid>
26                </Container>
27                <Button variant="contained" size="large" sx={{ position: "absolute", bottom: "10%", left: "50%", transform: "translateX(-50%)" }}>
28                    LearnMore
29                </Button>
30            </Box>
31            <Box>
32                <Container maxWidth='md'>
33                    <SkillList />
34                </Container>
35            </Box>
36            <Box>
37                <Container maxWidth='md'>
38                    <ProductionList />
39                </Container>
40            </Box>
41            <Box>
42                <Container maxWidth='md'>
43                    <ProfileList />
44                </Container>
45            </Box>
46+             <Box>
47+                 <Container maxWidth='md'>
48+                     <ContactForm />
49+                 </Container>
50+             </Box>
51        </>

ContactFormコンポーネントをインポートし、お問い合わせコンテンツでContactFormコンポーネントを呼び出す形にしています。

おわりに

Reactでお問い合わせフォームを実装する手順を解説していきましたが、いかがだったでしょうか。 Webサイトのお問い合わせフォームはユーザーが運営側にコンタクトをとれる重要なコンテンツになりますので、入力内容のバリデーションやメール送信前に確認画面を表示させるなども検討するともっと良いかと思います。 是非、Reactでモダンでおしゃれなお問い合わせフォームを作っていきましょう。

関連コンテンツ

【React】簡単なお問い合わせフォームの実装|ポートフォリオサイトの作り方 | いっしー@Webエンジニア