2025年6月1日日曜日

【第9回】React Hook Form:フォーム入力内容のローカルストレージ保存

# 【第9回】React Hook Form:フォーム入力内容のローカルストレージ保存

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIを使ってモダンなWebアプリを開発する方法をステップバイステップで解説しています。

第9回となる今回は、React Hook Form を使用して、フォーム入力内容をローカルストレージに保存・復元する機能を実装します。ユーザーが入力途中で画面を閉じても、次回アクセス時に入力内容を復元できる機能を作ります。

📦 使用する技術スタック

ツール バージョン 説明
React Hook Form v7.x 高性能なフォームバリデーションライブラリ
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🎯 今回のゴール

  • フォーム入力内容の自動保存機能の実装
  • 保存したデータの復元機能の実装
  • データのクリア機能の実装

🚀 実装手順

1. プロジェクトの作成

まずは、Viteを使って新しいプロジェクトを作成します:

npm create vite@latest react-form-storage -- --template react-ts
cd react-form-storage
npm install

2. 必要なパッケージのインストール

MUIとReact Hook Formをインストールします:

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material react-hook-form

3. カスタムフックの作成

src/hooks/useLocalStorage.tsを作成します:

import { useState, useEffect } from "react";

export function useLocalStorage(key: string, initialValue: T) {
  // 初期値の設定
  const [storedValue, setStoredValue] = useState(() => {
    try {
      const item = window.localStorage.getItem(key);
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      console.error(error);
      return initialValue;
    }
  });

  // 値の更新時にローカルストレージも更新
  useEffect(() => {
    try {
      window.localStorage.setItem(key, JSON.stringify(storedValue));
    } catch (error) {
      console.error(error);
    }
  }, [key, storedValue]);

  return [storedValue, setStoredValue] as const;
}

4. フォームコンポーネントの作成

src/components/PersistentForm.tsxを作成します:

import { useEffect } from "react";
import { useForm } from "react-hook-form";
import {
  Box,
  Button,
  Container,
  TextField,
  Typography,
} from "@mui/material";
import { useLocalStorage } from "../hooks/useLocalStorage";
import type { FC } from "react";

type FormValues = {
  name: string;
  email: string;
  message: string;
};

const STORAGE_KEY = "form_data";

const PersistentForm: FC = () => {
  const [storedData, setStoredData] = useLocalStorage>(
    STORAGE_KEY,
    {}
  );

  const {
    register,
    handleSubmit,
    reset,
    watch,
    formState: { errors },
  } = useForm({
    defaultValues: storedData,
  });

  // フォームの値が変更されたら自動保存
  useEffect(() => {
    const subscription = watch((value) => {
      setStoredData(value);
    });
    return () => subscription.unsubscribe();
  }, [watch, setStoredData]);

  const onSubmit = (data: FormValues) => {
    console.log("送信データ:", data);
    alert(JSON.stringify(data, null, 2));
    // 送信成功時にフォームとストレージをクリア
    reset();
    setStoredData({});
  };

  const handleClear = () => {
    reset();
    setStoredData({});
  };

  return (
    <Container maxWidth="sm">
      <Box mt={5}>
        <Typography variant="h5" gutterBottom>
          永続化フォーム
        </Typography>
        <form onSubmit={handleSubmit(onSubmit)} noValidate>
          <Box display="flex" flexDirection="column" gap={2}>
            <TextField
              fullWidth
              label="名前"
              {...register("name", { required: "名前は必須です" })}
              error={Boolean(errors.name)}
              helperText={errors.name?.message}
            />
            <TextField
              fullWidth
              label="メール"
              {...register("email", {
                required: "メールは必須です",
                pattern: {
                  value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
                  message: "メール形式が不正です",
                },
              })}
              error={Boolean(errors.email)}
              helperText={errors.email?.message}
            />
            <TextField
              fullWidth
              label="メッセージ"
              multiline
              rows={4}
              {...register("message", {
                required: "メッセージは必須です",
                minLength: {
                  value: 10,
                  message: "10文字以上入力してください",
                },
              })}
              error={Boolean(errors.message)}
              helperText={errors.message?.message}
            />
            <Box
              display="flex"
              justifyContent="space-between"
              alignItems="center"
            >
              <Button
                variant="outlined"
                color="secondary"
                onClick={handleClear}
              >
                クリア
              </Button>
              <Button type="submit" variant="contained" color="primary">
                送信
              </Button>
            </Box>
          </Box>
        </form>
      </Box>
    </Container>
  );
};

export default PersistentForm;

5. App.tsxの更新

最後に、src/App.tsxを更新してフォームを表示します:

import PersistentForm from "./components/PersistentForm";
import type { FC } from "react";

const App: FC = () => {
  return ;
};

export default App;

🎯 主要なポイント

1. カスタムフック設計

  • 型安全性: ジェネリクスを使用した柔軟な型定義
  • エラーハンドリング: try-catchによる安全な処理
  • 永続化: useEffectによる自動保存の実装

2. フォーム機能

  • 自動保存: watchによる入力値の変更検知
  • データ復元: defaultValuesによる初期値の設定
  • クリア機能: フォームとストレージの同時クリア

3. UX設計

  • バリデーション: リアルタイムな入力検証
  • フィードバック: エラーメッセージの表示
  • 操作性: クリアと送信の2つのアクション

🔚 まとめ

今回は、React Hook Form と localStorage を組み合わせて、フォーム入力内容を永続化する機能を実装しました。 この実装により、以下のメリットが得られます:

  • ✅ 入力内容の保持: ブラウザを閉じても入力内容が失われない
  • 🔄 自動保存: 入力内容がリアルタイムで保存される
  • 🗑️ データ管理: 必要に応じて入力内容をクリア可能

📚 次回予告

【第10回】React Hook Form:フォームの状態管理とコンテキスト

2025年5月28日水曜日

【第8回】React Hook Form × MUI:ステップフォームの実装

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIを使ってモダンなWebアプリを開発する方法をステップバイステップで解説しています。

第8回となる今回は、React Hook Form と MUI を使って、ユーザーの入力体験を向上させる ステップフォーム(Step Form) を実装します。

フォームを複数のページに分けて入力させることで、長いフォームでもストレスなく入力できる UI を実現します。

📦 使用する技術スタック

ツール バージョン 説明
React Hook Form v7.x 高性能なフォームバリデーションライブラリ
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🎯 今回のゴール

  • フォームの入力を段階的に表示
  • 各ステップでバリデーション
  • 最後に確認画面と送信

🚀 実装手順

1. プロジェクトの作成

まずは、Viteを使って新しいプロジェクトを作成します:

npm create vite@latest react-step-form -- --template react-ts
cd react-step-form
npm install

2. 必要なパッケージのインストール

MUIとReact Hook Formをインストールします:

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material react-hook-form

3. プロジェクト構成

今回のプロジェクトは以下のような構成になります:

src/
  ├── components/
  │   ├── StepOne.tsx
  │   ├── StepTwo.tsx
  │   └── Confirmation.tsx
  ├── StepForm.tsx
  └── App.tsx

4. 型定義の作成

まず、共通で使用する型を定義します:

type FormValues = {
  name: string;
  email: string;
};

5. 各ステップコンポーネントの作成

src/components/StepOne.tsx(名前入力):

import { TextField } from "@mui/material";
import { useFormContext } from "react-hook-form";
import type { FC } from "react";
import type { FormValues } from "../types";

const StepOne: FC = () => {
  const {
    register,
    formState: { errors },
  } = useFormContext<FormValues>();

  return (
    <TextField
      fullWidth
      label="名前"
      {...register("name", { required: "名前は必須です" })}
      error={!!errors.name}
      helperText={errors.name?.message}
    />
  );
};

export default StepOne;

src/components/StepTwo.tsx(メール入力):

import { TextField } from "@mui/material";
import { useFormContext } from "react-hook-form";
import type { FC } from "react";
import type { FormValues } from "../types";

const StepTwo: FC = () => {
  const {
    register,
    formState: { errors },
  } = useFormContext<FormValues>();

  return (
    <TextField
      fullWidth
      label="メール"
      {...register("email", {
        required: "メールは必須です",
        pattern: {
          value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
          message: "メール形式が不正です",
        },
      })}
      error={!!errors.email}
      helperText={errors.email?.message}
    />
  );
};

export default StepTwo;

src/components/Confirmation.tsx(確認画面):

import { Typography } from "@mui/material";
import { useFormContext } from "react-hook-form";
import type { FC } from "react";
import type { FormValues } from "../types";

const Confirmation: FC = () => {
  const { getValues } = useFormContext<FormValues>();
  const { name, email } = getValues();

  return (
    <>
      <Typography>名前: {name}</Typography>
      <Typography>メール: {email}</Typography>
    </>
  );
};

export default Confirmation;

6. メインフォームコンポーネントの作成

src/StepForm.tsx:

import {
  Box,
  Button,
  Container,
  Step,
  StepLabel,
  Stepper,
  Typography,
} from "@mui/material";
import { useState } from "react";
import { FormProvider, useForm } from "react-hook-form";
import StepOne from "./components/StepOne";
import StepTwo from "./components/StepTwo";
import Confirmation from "./components/Confirmation";
import type { FC } from "react";
import type { FormValues } from "./types";

const steps = ["名前入力", "メール入力", "確認"] as const;

const StepForm: FC = () => {
  const methods = useForm<FormValues>({
    defaultValues: {
      name: "",
      email: "",
    },
  });
  const [step, setStep] = useState(0);

  const onNext = async () => {
    const valid = await methods.trigger();
    if (valid) setStep((prev) => prev + 1);
  };

  const onBack = () => setStep((prev) => prev - 1);

  const onSubmit = (data: FormValues) => {
    console.log(JSON.stringify(data, null, 2));
  };

  const renderStep = () => {
    switch (step) {
      case 0:
        return <StepOne />;
      case 1:
        return <StepTwo />;
      case 2:
        return <Confirmation />;
      default:
        return null;
    }
  };

  return (
    <FormProvider {...methods}>
      <Container maxWidth="sm">
        <Box mt={5}>
          <Typography variant="h5" gutterBottom>
            ステップフォーム
          </Typography>

          <Stepper activeStep={step}>
            {steps.map((label) => (
              <Step key={label}>
                <StepLabel>{label}</StepLabel>
              </Step>
            ))}
          </Stepper>

          <Box mt={4} mb={2}>
            <form onSubmit={methods.handleSubmit(onSubmit)}>
              <Box display="flex" flexDirection="column" gap={2}>
                {renderStep()}

                <Box display="flex" justifyContent="space-between">
                  {step > 0 && (
                    <Button variant="outlined" onClick={onBack}>
                      戻る
                    </Button>
                  )}
                  {step < steps.length - 1 ? (
                    <Button variant="contained" onClick={onNext}>
                      次へ
                    </Button>
                  ) : (
                    <Button type="submit" variant="contained" color="primary">
                      送信
                    </Button>
                  )}
                </Box>
              </Box>
            </form>
          </Box>
        </Box>
      </Container>
    </FormProvider>
  );
};

export default StepForm;

7. App.tsxの更新

最後に、src/App.tsxを更新してフォームを表示します:

import StepForm from "./StepForm";
import type { FC } from "react";

const App: FC = () => {
  return <StepForm />;
};

export default App;

🎯 主要なポイント

1. フォーム状態の共有

  • FormProvider: すべてのステップでフォームの状態を共有
  • useFormContext: 子コンポーネントからのフォーム操作を簡単に
  • 型安全性: TypeScriptによる厳密な型チェック

2. ステップ管理

  • useState: 現在のステップを管理
  • trigger(): 次のステップへ進む前にバリデーション
  • 条件付きレンダリング: 現在のステップに応じたコンポーネント表示

3. UI/UX設計

  • Stepper: 進捗状況を視覚的に表示
  • ナビゲーション: 戻る/次へ/送信ボタンの適切な表示
  • バリデーション: 各ステップでの入力チェック

🔚 まとめ

今回は、React Hook Form × MUI を用いて複数ステップで構成されるフォームを作成しました。これにより、ユーザーにとって負担の少ない入力体験が提供できます。

📚 次回予告

【第9回】React Hook Form:フォーム入力内容のローカルストレージ保存

2025年5月26日月曜日

【第7回】React Hook Form × MUI:フォームをコンポーネント単位で分割する設計手法

# 【第7回】React Hook Form × MUI:フォームをコンポーネント単位で分割する設計手法

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIを使ってモダンなWebアプリを開発する方法をステップバイステップで解説しています。

第7回となる今回は、「フォームをコンポーネント単位で分割する設計手法」について解説します。前回作成したフォームをベースに、入力フィールドを個別のコンポーネントに分割し、保守性と再利用性を高める実装方法を学んでいきます。

📦 使用する技術スタック

ツール バージョン 説明
React Hook Form v7.x 高性能なフォームバリデーションライブラリ
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🚀 実装手順

1. プロジェクトの作成

まずは、Viteを使って新しいプロジェクトを作成します:

npm create vite@latest react-form-components -- --template react-ts
cd react-form-components
npm install

2. 必要なパッケージのインストール

MUIとReact Hook Formをインストールします:

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material react-hook-form

3. プロジェクト構成

今回のプロジェクトは以下のような構成になります:

src/
  ├── components/
  │   ├── NameField.tsx
  │   └── EmailField.tsx
  ├── FormComponent.tsx
  └── App.tsx

4. 入力フィールドコンポーネントの作成

まず、src/components/NameField.tsxを作成します:

import { TextField } from "@mui/material";
import { useForm } from "react-hook-form";
import type { FC } from "react";

type Props = {
  register: ReturnType<typeof useForm>["register"];
  error?: string;
};

const NameField: FC<Props> = ({ register, error }) => {
  return (
    <TextField
      fullWidth
      label="名前"
      {...register("name", { required: "名前は必須です" })}
      error={Boolean(error)}
      helperText={error}
    />
  );
};

export default NameField;

次に、src/components/EmailField.tsxを作成します:

import { TextField } from "@mui/material";
import { useForm } from "react-hook-form";
import type { FC } from "react";

type Props = {
  register: ReturnType<typeof useForm>["register"];
  error?: string;
};

const EmailField: FC<Props> = ({ register, error }) => {
  return (
    <TextField
      fullWidth
      label="メール"
      {...register("email", {
        required: "メールは必須です",
        pattern: {
          value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
          message: "メール形式が不正です",
        },
      })}
      error={Boolean(error)}
      helperText={error}
    />
  );
};

export default EmailField;

5. メインフォームコンポーネントの作成

src/FormComponent.tsxを作成します:

import { useForm, type FieldValues, type UseFormRegister } from "react-hook-form";
import { Box, Button, Container, Typography } from "@mui/material";
import NameField from "./components/NameField";
import EmailField from "./components/EmailField";
import type { FC } from "react";

type FormValues = {
  name: string;
  email: string;
};

const FormComponent: FC = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>();

  const onSubmit = (data: FormValues) => {
    console.log("送信データ:", data);
    alert(JSON.stringify(data, null, 2));
  };

  return (
    <Container maxWidth="sm">
      <Box mt={5}>
        <Typography variant="h5" gutterBottom>
          コンポーネント分割フォーム
        </Typography>
        <form onSubmit={handleSubmit(onSubmit)} noValidate>
          <Box display="flex" flexDirection="column" gap={2}>
            <NameField
              register={register as unknown as UseFormRegister<FieldValues>}
              error={errors.name?.message}
            />
            <EmailField
              register={register as unknown as UseFormRegister<FieldValues>}
              error={errors.email?.message}
            />
            <Box textAlign="center">
              <Button type="submit" variant="contained" color="primary">
                送信
              </Button>
            </Box>
          </Box>
        </form>
      </Box>
    </Container>
  );
};

export default FormComponent;

6. App.tsxの更新

最後に、src/App.tsxを更新してフォームを表示します:

import FormComponent from "./FormComponent";
import type { FC } from "react";

const App: FC = () => {
  return <FormComponent />;
};

export default App;

🎯 主要なポイント

1. コンポーネント設計

  • 単一責任の原則: 各コンポーネントは1つの役割に特化
  • 再利用性: 入力フィールドを独立したコンポーネントとして実装
  • 型安全性: TypeScriptによる厳密な型チェック

2. Props設計

  • register関数: React Hook Formの登録関数を適切に受け渡し
  • エラー処理: エラーメッセージを親から子へ伝播
  • 型定義: 明確なPropsの型定義による安全性確保

3. フォーム管理

  • 状態管理: useFormによる一元的なフォーム状態管理
  • バリデーション: 各フィールドでの個別バリデーション定義
  • 送信処理: handleSubmitによる統一的な送信処理

🔚 まとめ

今回は、React Hook Formを使用したフォームをコンポーネント単位に分割する設計手法について学びました。この設計により、以下のメリットが得られます:

  • ✅ 保守性の向上: 各コンポーネントが独立して管理可能
  • 🔄 再利用性の向上: 共通の入力フィールドを別のフォームでも使用可能
  • 📝 コードの可読性向上: 責任範囲が明確で理解しやすい構造

📚 次回予告

【第8回】React Hook Form × MUI:ステップフォームの実装

【第6回】バリデーション結果をモーダルで表示するReact Hook Form実装

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIを使ってモダンなWebアプリを開発する方法をステップバイステップで解説しています。

第6回となる今回は、「バリデーション結果をモーダルで表示するReact Hook Form実装」に取り組みます。前回作成したフォームをベースに、バリデーションエラーや送信内容の確認結果をモーダル(ダイアログ)で表示するUIを実装していきます。

📦 使用する技術スタック

ツール バージョン 説明
React Hook Form v7.x 高性能なフォームバリデーションライブラリ
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🚀 実装手順

1. プロジェクトの作成

まずは、Viteを使って新しいプロジェクトを作成します:

npm create vite@latest react-form-modal -- --template react-ts
cd react-form-modal
npm install

2. 必要なパッケージのインストール

MUIとReact Hook Formをインストールします:

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material react-hook-form @fontsource/roboto

3. モーダル付きフォームの作成

src/FormWithModal.tsxを作成します:

import { useForm } from "react-hook-form"
import {
  Box,
  Button,
  Container,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogActions,
  TextField,
  Typography,
} from "@mui/material"
import { useState } from "react"

type FormValues = {
  name: string
  email: string
}

export default function FormWithModal() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>({
    defaultValues: {
      name: "",
      email: "",
    },
  })

  const [open, setOpen] = useState(false)
  const [submittedData, setSubmittedData] = useState<FormValues | null>(null)

  const onSubmit = (data: FormValues) => {
    setSubmittedData(data)
    setOpen(true)
  }

  return (
    <Container maxWidth="sm">
      <Box mt={5}>
        <Typography variant="h5" gutterBottom>
          モーダル表示付きフォーム
        </Typography>
        <form onSubmit={handleSubmit(onSubmit)} noValidate>
          <Box display="flex" flexDirection="column" gap={2}>
            <TextField
              label="名前"
              fullWidth
              {...register("name", { required: "名前は必須です" })}
              error={Boolean(errors.name)}
              helperText={errors.name?.message}
            />
            <TextField
              label="メール"
              fullWidth
              {...register("email", {
                required: "メールは必須です",
                pattern: {
                  value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
                  message: "メール形式が不正です",
                },
              })}
              error={Boolean(errors.email)}
              helperText={errors.email?.message}
            />
            <Button type="submit" variant="contained" color="primary">
              送信
            </Button>
          </Box>
        </form>
      </Box>
      <Dialog open={open} onClose={() => setOpen(false)}>
        <DialogTitle>送信内容の確認</DialogTitle>
        <DialogContent dividers>
          {submittedData && (
            <Box>
              <Typography>名前: {submittedData.name}</Typography>
              <Typography>メール: {submittedData.email}</Typography>
            </Box>
          )}
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setOpen(false)} color="primary">
            閉じる
          </Button>
        </DialogActions>
      </Dialog>
    </Container>
  )
}

4. App.tsxの更新

最後に、src/App.tsxを更新してフォームを表示します:

import { ThemeProvider, createTheme } from '@mui/material'
import FormWithModal from "./FormWithModal"
import '@fontsource/roboto/300.css'
import '@fontsource/roboto/400.css'
import '@fontsource/roboto/500.css'
import '@fontsource/roboto/700.css'

const theme = createTheme({
  typography: {
    fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
  },
})

function App() {
  return (
    <ThemeProvider theme={theme}>
      <FormWithModal />
    </ThemeProvider>
  )
}

export default App

🎯 主要なポイント

1. モーダル管理

  • Dialog コンポーネント: MUIのモーダルダイアログを使用
  • 状態管理: useStateでモーダルの開閉を制御
  • 送信データ: 確認用モーダルに表示するデータを保持

2. フォーム機能

  • バリデーション: 名前とメールアドレスの入力検証
  • エラー表示: フィールド単位でのエラーメッセージ表示
  • 送信処理: フォームデータをモーダルで確認

3. UIコンポーネント

  • Dialog関連: タイトル、コンテンツ、アクションの3層構造
  • TextField: エラー状態とメッセージの統合
  • レイアウト: Boxコンポーネントによる柔軟な配置

🔚 まとめ

今回は、React Hook FormとMUIのDialogコンポーネントを組み合わせて、ユーザーフレンドリーなフォームを実装しました。バリデーション結果や送信内容をモーダルで表示することで、より分かりやすいUIを実現できました。

📚 次回予告

【第7回】React Hook Form × MUI:フォームをコンポーネント単位で分割する設計手法

【第5回】React Hook Formによるフォーム処理の実践 - 複数メールアドレスの処理

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIを使ってモダンなWebアプリを開発する方法をステップバイステップで解説しています。

第5回となる今回は、「React Hook Formを使った複数メールアドレスの入力フォーム」を実装します。useFieldArrayを使用した動的なフォーム要素の追加・削除と、効果的なバリデーション処理を学びます。

📦 使用する技術スタック

ツール バージョン 説明
React Hook Form v7.x 高性能なフォームバリデーションライブラリ
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🚀 実装手順

1. プロジェクトの作成

まずは、Viteを使って新しいプロジェクトを作成します:

npm create vite@latest react-form-advanced -- --template react-ts
cd react-form-advanced
npm install

2. 必要なパッケージのインストール

MUIとReact Hook Formをインストールします:

npm install @mui/material @emotion/react @emotion/styled @mui/icons-material react-hook-form @fontsource/roboto

3. 複数メール入力フォームの作成

src/AdvancedForm.tsxを作成します:

import type { FC } from "react"
import { useForm, useFieldArray } from "react-hook-form"
import {
  Box,
  Button,
  Container,
  TextField,
  Typography,
} from "@mui/material"
import { Add, Delete } from "@mui/icons-material"

type FormValues = {
  name: string
  emails: { email: string }[]
}

const AdvancedForm: FC = () => {
  const {
    register,
    control,
    handleSubmit,
    formState: { errors },
  } = useForm<FormValues>({
    defaultValues: {
      name: "",
      emails: [{ email: "" }],
    },
  })

  const { fields, append, remove } = useFieldArray({
    control,
    name: "emails",
  })

  const onSubmit = (data: FormValues) => {
    console.log("送信データ:", data)
    alert(JSON.stringify(data, null, 2))
  }

  return (
    <Container maxWidth="sm">
      <Box mt={5}>
        <Typography variant="h5" gutterBottom>
          高度なフォーム(React Hook Form + MUI)
        </Typography>
        <form onSubmit={handleSubmit(onSubmit)} noValidate>
          <Box display="flex" flexDirection="column" gap={2}>
            <Box>
              <TextField
                fullWidth
                label="名前"
                {...register("name", { required: "名前は必須です" })}
                error={Boolean(errors.name)}
                helperText={errors.name?.message}
              />
            </Box>
            {fields.map((field, index) => (
              <Box key={field.id}>
                <Box display="flex" alignItems="center" gap={1}>
                  <TextField
                    fullWidth
                    label={`メール ${index + 1}`}
                    {...register(`emails.${index}.email`, {
                      required: "メールは必須です",
                      pattern: {
                        value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
                        message: "メール形式が不正です",
                      },
                    })}
                    error={Boolean(errors.emails?.[index]?.email)}
                    helperText={errors.emails?.[index]?.email?.message}
                  />
                  <Button
                    variant="outlined"
                    color="secondary"
                    onClick={() => remove(index)}
                  >
                    <Delete />
                  </Button>
                </Box>
              </Box>
            ))}
            <Box>
              <Button
                variant="outlined"
                startIcon={<Add />}
                onClick={() => append({ email: "" })}
              >
                メール追加
              </Button>
            </Box>
            <Box mt={2} display="flex" justifyContent="center">
              <Button type="submit" variant="contained" color="primary">
                送信
              </Button>
            </Box>
          </Box>
        </form>
      </Box>
    </Container>
  )
}

export default AdvancedForm

4. App.tsxの更新

src/App.tsxを更新してフォームを表示します:

import { ThemeProvider, createTheme } from '@mui/material'
import AdvancedForm from "./AdvancedForm"
import '@fontsource/roboto/300.css'
import '@fontsource/roboto/400.css'
import '@fontsource/roboto/500.css'
import '@fontsource/roboto/700.css'

const theme = createTheme({
  typography: {
    fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
  },
})

function App() {
  return (
    <ThemeProvider theme={theme}>
      <AdvancedForm />
    </ThemeProvider>
  )
}

export default App

🎯 主要なポイント

1. フォーム状態管理

  • useForm: フォーム全体の状態とバリデーション管理
  • useFieldArray: 動的なフィールド配列の管理
  • 型安全な実装: TypeScriptによる型定義

2. バリデーション機能

  • 必須チェック: 名前とメールアドレスの入力必須
  • メール形式: 正規表現によるメールアドレス形式の検証
  • 視覚的フィードバック: エラーメッセージの即時表示

3. UIコンポーネント

  • TextField: 入力フィールドとエラー表示の統合
  • Button: アイコン付きの操作ボタン
  • 動的なUI: フィールドの追加・削除機能

🔚 まとめ

今回は、React Hook Form の useFieldArray を使って、複数メール入力のフォームを実装しました。 動的なフォーム要素の管理とバリデーション処理を効率的に実装できることが分かりました。

📚 次回予告

【第6回】バリデーション結果をモーダルで表示するReact Hook Form実装

2025年5月25日日曜日

【第4回】状態管理とAPI通信(React + Axios)

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIを使ってモダンなWebアプリを開発する方法をステップバイステップで解説しています。

第4回となる今回は、「外部APIとの通信(Axios)」と「状態管理(useState, useEffect)」を学びます。APIから取得したデータを画面に表示する実践的な構成です。

📦 使用する技術スタック

ツール バージョン 説明
Axios v1.x HTTP通信を行う人気のライブラリ
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🚀 実装手順

1. プロジェクトの作成

まずは、Viteを使って新しいプロジェクトを作成します:

npm create vite@latest react-api-app -- --template react-ts
cd react-api-app
npm install

2. 必要なパッケージのインストール

MUIとAxiosをインストールします:

npm install @mui/material @emotion/react @emotion/styled @fontsource/roboto axios

3. ユーザー一覧コンポーネントの作成

src/pages/UserList.tsxを作成します:

import type { FC } from 'react';
import { useEffect, useState } from 'react';
import type { AxiosResponse } from 'axios';
import axios from 'axios';
import {
  Container,
  Typography,
  List,
  ListItem,
  ListItemText,
  CircularProgress,
  Alert,
  Paper
} from '@mui/material';

type User = {
  id: number;
  name: string;
  email: string;
};

const UserList: FC = () => {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  useEffect(() => {
    axios.get<User[]>('https://jsonplaceholder.typicode.com/users')
      .then((res: AxiosResponse<User[]>) => {
        setUsers(res.data);
        setLoading(false);
      })
      .catch(() => {
        setError('ユーザーの取得に失敗しました。');
        setLoading(false);
      });
  }, []);

  if (loading) {
    return (
      <Container maxWidth="sm">
        <Paper elevation={3} sx={{ p: 4, mt: 4, textAlign: 'center' }}>
          <CircularProgress />
        </Paper>
      </Container>
    );
  }

  if (error) {
    return (
      <Container maxWidth="sm">
        <Paper elevation={3} sx={{ p: 4, mt: 4 }}>
          <Alert severity="error">{error}</Alert>
        </Paper>
      </Container>
    );
  }

  return (
    <Container maxWidth="sm">
      <Paper elevation={3} sx={{ p: 4, mt: 4 }}>
        <Typography variant="h4" component="h1" gutterBottom>
          ユーザー一覧
        </Typography>
        <List>
          {users.map(user => (
            <ListItem key={user.id} divider>
              <ListItemText 
                primary={user.name} 
                secondary={user.email}
              />
            </ListItem>
          ))}
        </List>
      </Paper>
    </Container>
  );
};

export default UserList;

4. App.tsxの更新

最後に、src/App.tsxを更新してユーザー一覧を表示します:

import { ThemeProvider, createTheme } from '@mui/material';
import UserList from './pages/UserList';
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';

const theme = createTheme({
  typography: {
    fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <UserList />
    </ThemeProvider>
  );
}

export default App;

🎯 主要なポイント

1. 状態管理

  • useState: データ、ローディング、エラー状態の管理
  • useEffect: コンポーネントマウント時のAPI呼び出し
  • 型安全な状態管理: TypeScriptによる型定義

2. API通信

  • Axios: 型安全なHTTPクライアント
  • エラーハンドリング: try-catchによる例外処理
  • ローディング表示: ユーザー体験の向上

3. UIコンポーネント

  • List/ListItem: データの一覧表示
  • CircularProgress: ローディング表示
  • Alert: エラーメッセージの表示

🔚 まとめ

今回は、Reactで外部APIからデータを取得し、それを状態として管理して表示する方法を学びました。MUIとAxiosを組み合わせることで、実用的な画面が簡単に作成できることが実感できたと思います。

📚 次回予告

【第5回】React Hook Formによるフォーム処理の実践 - 複数メールアドレスの処理

【第3回】フォームの作成とバリデーション(MUI + React Hook Form)

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIという現代的な技術スタックを使って、Webアプリを開発する方法をステップバイステップで解説しています。

第3回となる今回は、フォームの作成とバリデーションを扱います。UIには MUI を、バリデーションには React Hook Form を使って、シンプルかつ堅牢なフォームを作成していきましょう。

📦 使用する技術スタック

ツール バージョン 説明
React Hook Form v7.x フォーム管理とバリデーション
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🚀 実装手順

1. プロジェクトの作成

まずは、Viteを使って新しいプロジェクトを作成します:

npm create vite@latest my-react-form-app -- --template react-ts
cd my-react-form-app
npm install

2. 必要なパッケージのインストール

MUIとReact Hook Formをインストールします:

npm install @mui/material @emotion/react @emotion/styled @fontsource/roboto react-hook-form

3. フォームコンポーネントの作成

src/pages/UserForm.tsxを作成します:

import type { FC } from 'react';
import { useForm } from 'react-hook-form';
import { TextField, Button, Container, Typography, Paper } from '@mui/material';

type FormData = {
  name: string;
  email: string;
};

const UserForm: FC = () => {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>();

  const onSubmit = (data: FormData): void => {
    alert(`名前: ${data.name}\nメール: ${data.email}`);
  };

  return (
    <Container maxWidth="sm">
      <Paper elevation={3} sx={{ p: 4, mt: 4 }}>
        <Typography variant="h4" component="h1" gutterBottom>
          ユーザーフォーム
        </Typography>
        <form onSubmit={handleSubmit(onSubmit)} noValidate>
          <TextField
            fullWidth
            label="名前"
            margin="normal"
            {...register('name', { required: '名前は必須です' })}
            error={!!errors.name}
            helperText={errors.name?.message}
          />
          <TextField
            fullWidth
            label="メール"
            margin="normal"
            {...register('email', {
              required: 'メールは必須です',
              pattern: {
                value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
                message: '有効なメールアドレスを入力してください',
              },
            })}
            error={!!errors.email}
            helperText={errors.email?.message}
          />
          <Button 
            variant="contained" 
            type="submit" 
            sx={{ mt: 2 }}
            fullWidth
          >
            送信
          </Button>
        </form>
      </Paper>
    </Container>
  );
};

export default UserForm;

4. App.tsxの更新

最後に、src/App.tsxを更新してフォームを表示します:

import { ThemeProvider, createTheme } from '@mui/material';
import UserForm from './pages/UserForm';

const theme = createTheme({
  typography: {
    fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <UserForm />
    </ThemeProvider>
  );
}

export default App;

🎯 主要なポイント

1. React Hook Formの基本概念

  • useForm: フォームの状態管理とバリデーションを提供
  • register: フォームフィールドの登録とバリデーションルールの設定
  • handleSubmit: フォーム送信時の処理を管理
  • formState: エラー状態などのフォーム状態を管理

2. MUIフォームコンポーネント

  • TextField: 入力フィールドのスタイリングとエラー表示
  • Container: レスポンシブなレイアウト
  • Paper: カード風のコンテナスタイリング

3. TypeScriptの型安全性

  • FC型: Reactの関数コンポーネントの型定義
  • FormData型: フォームデータの型定義
  • 明示的な戻り値の型: 関数の戻り値型を指定

🔚 まとめ

今回は、React Hook FormとMUIを組み合わせて、型安全なバリデーション機能付きフォームを実装しました。この組み合わせは実用的で、多くの商用アプリでも採用されています。

📚 次回予告

【第4回】状態管理とAPI通信(React + Axios)

2025年5月24日土曜日

【第2回】React Routerで画面遷移を実装しよう!

✅ はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIという現代的な技術スタックを使って、Webアプリを開発する方法をステップバイステップで解説していきます。

第2回となる今回は、React Routerを使って「複数のページを持つアプリケーション」を作成します。画面遷移やルーティングの仕組みを理解することで、より本格的なアプリ開発ができるようになります!

📦 使用する技術スタック

ツール バージョン 説明
React Router v6.x Reactアプリケーションのルーティングライブラリ
MUI v5.x マテリアルデザインベースのUIコンポーネント
TypeScript 5.x 型安全なJavaScript
Vite 5.x 高速な開発環境とビルドツール

🚀 実装手順

1. 必要なパッケージのインストール

npm install react-router-dom @mui/material @emotion/react @emotion/styled @fontsource/roboto

2. ページコンポーネントの作成

src/pages/Home.tsx

import { Container, Typography, Paper, Box } from '@mui/material';

const Home = () => {
  return (
    <Container maxWidth="md">
      <Paper elevation={3} sx={{ p: 4, mt: 4 }}>
        <Typography variant="h4" component="h1" gutterBottom>
          ホームページ
        </Typography>
        <Box sx={{ mt: 2 }}>
          <Typography variant="body1">
            このアプリケーションは、React Router v6を使用した
            シンプルなルーティングのデモンストレーションです。
          </Typography>
        </Box>
      </Paper>
    </Container>
  );
};

export default Home;

src/pages/About.tsx

import { Container, Typography, Paper, Box, List, ListItem, ListItemText } from '@mui/material';

const About = () => {
  return (
    <Container maxWidth="md">
      <Paper elevation={3} sx={{ p: 4, mt: 4 }}>
        <Typography variant="h4" component="h1" gutterBottom>
          このアプリについて
        </Typography>
        <Box sx={{ mt: 2 }}>
          <Typography variant="body1" paragraph>
            このアプリケーションは以下の技術スタックを使用しています:
          </Typography>
          <List>
            <ListItem>
              <ListItemText 
                primary="React + TypeScript" 
                secondary="型安全なコンポーネント開発"
              />
            </ListItem>
            <ListItem>
              <ListItemText 
                primary="React Router v6" 
                secondary="モダンなルーティング機能"
              />
            </ListItem>
            <ListItem>
              <ListItemText 
                primary="Material-UI (MUI)" 
                secondary="美しいUIコンポーネント"
              />
            </ListItem>
          </List>
        </Box>
      </Paper>
    </Container>
  );
};

export default About;

3. App.tsxでのルーティング設定

import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
import { 
  AppBar, 
  Toolbar, 
  Button, 
  Container, 
  ThemeProvider, 
  createTheme,
  Box,
  Typography
} from '@mui/material';
import Home from './pages/Home';
import About from './pages/About';

const theme = createTheme({
  typography: {
    fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
  },
});

function App() {
  return (
    <ThemeProvider theme={theme}>
      <BrowserRouter>
        <Box sx={{ flexGrow: 1 }}>
          <AppBar position="static">
            <Toolbar>
              <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
                React Router Demo
              </Typography>
              <Button 
                color="inherit" 
                component={Link} 
                to="/"
                sx={{ mr: 2 }}
              >
                Home
              </Button>
              <Button 
                color="inherit" 
                component={Link} 
                to="/about"
              >
                About
              </Button>
            </Toolbar>
          </AppBar>
        </Box>

        <Container>
          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/about" element={<About />} />
          </Routes>
        </Container>
      </BrowserRouter>
    </ThemeProvider>
  );
}

export default App;

🎯 主要なポイント

1. React Routerの基本概念

  • BrowserRouter: URLベースのルーティングを提供
  • Routes: ルート定義のコンテナ
  • Route: 個別のルートを定義
  • Link: ページ間のナビゲーション

2. MUIとの統合

  • AppBarによるナビゲーションバー
  • Containerによるレイアウト
  • Buttonコンポーネントとリンクの統合

3. 型安全性

  • TypeScriptによる型チェック
  • コンポーネントpropsの型定義

🔚 まとめ

このチュートリアルでは、React RouterとMUIを組み合わせて、モダンなナビゲーションを持つSPAを構築する方法を学びました。次回は、フォームの実装とバリデーションについて解説します。

📚 次回予告

【第3回】フォームの作成とバリデーション(MUI + React Hook Form)

【第1回】React + Vite + TypeScript + MUIで開発環境を最速構築しよう【2025年版】

✅はじめに

こんにちは!このシリーズでは、React + Vite + TypeScript + MUIという現代的な技術スタックを使って、Webアプリを開発する方法をステップバイステップで解説していきます。

第1回となる今回は、開発環境の構築と初期プロジェクトの作成、そしてMUIを使った簡単なUI表示までを行います。

📦使用する技術スタック

ツール バージョン 説明
React 19.1.0 フロントエンドJavaScriptライブラリ
Vite 6.3.5 爆速な開発環境を提供するビルドツール
TypeScript 5.8.3 型安全なJavaScriptのスーパーセット
MUI 7.1.0 Googleのマテリアルデザインに基づいたUIライブラリ

🛠1.必要なツールの準備

以下がインストールされていることを確認してください。

  • Node.js(最新版)
  • 任意のエディタ(例:Visual Studio Code)

🚀2.プロジェクトの作成

以下のコマンドをターミナルで実行して、Vite + React + TypeScript のプロジェクトを作成します。

npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm install

🎨3.MUIのインストール

次に、MUIのライブラリとRobotoフォントをインストールします。

npm install @mui/material @emotion/react @emotion/styled
npm install @fontsource/roboto

🧹4.index.cssを空にする

Vite のテンプレートには、初期状態でスタイルが含まれています。このスタイルは MUI のレイアウトに干渉するため、src/index.css の中身をすべて削除(もしくはコメントアウト)してください。

🧑‍💻5.main.tsxの編集

Robotoフォントを適用するために、src/main.tsxを以下のように編集します:

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'

// Robotoフォントのインポート
import '@fontsource/roboto/300.css';
import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

👨‍💻6.App.tsxの作成

次に、src/App.tsxを以下のように書き換えて、MUIのコンポーネントとRobotoフォントを使用したUIを作成します:

import { useState } from 'react'
import { Button, Container, Typography, ThemeProvider, createTheme, Box } from '@mui/material'

type CounterProps = {
  initialCount?: number;
};

// カスタムテーマを作成
const theme = createTheme({
  typography: {
    fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
  },
});

function App({ initialCount = 0 }: CounterProps) {
  const [count, setCount] = useState(initialCount)

  return (
    <ThemeProvider theme={theme}>
      <Container maxWidth="sm" sx={{ textAlign: 'center', mt: 5 }}>
        <Typography variant="h4" gutterBottom>
          React + Vite + MUI スターター
        </Typography>
        <Typography variant="body1" gutterBottom>
          カウント: {count}
        </Typography>
        <Button variant="contained" onClick={() => setCount(count + 1)}>
          カウントを増やす
        </Button>

        {/* フォントの比較表示 */}
        <Box sx={{ mt: 4, display: 'flex', flexDirection: 'column', gap: 2 }}>
          <Typography variant="h6">
            フォントの比較
          </Typography>
          <Typography sx={{ fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif' }}>
            これはRobotoフォントです (The quick brown fox jumps over the lazy dog)
          </Typography>
          <Typography sx={{ fontFamily: 'system-ui, -apple-system, sans-serif' }}>
            これはシステムフォントです (The quick brown fox jumps over the lazy dog)
          </Typography>
        </Box>
      </Container>
    </ThemeProvider>
  )
}

export default App

✨主な変更点と改善点

  1. Robotoフォントの追加: MUIのデフォルトフォントであるRobotoを正しく実装
  2. ThemeProviderの導入: フォントファミリーを明示的に設定し、一貫したデザインを実現
  3. TypeScriptの活用: CounterPropsインターフェースを定義し、型安全性を確保
  4. フォント比較機能: Robotoフォントとシステムフォントの違いを視覚的に確認可能

✅表示確認

以下のコマンドで開発サーバーを起動しましょう。

npm run dev

ブラウザでhttp://localhost:5173を開くと、以下の要素が確認できます:

  • Robotoフォントを使用したヘッダーテキスト
  • カウンター機能付きのボタン
  • フォントの違いを確認できる比較セクション

🔚まとめ

これで、React + Vite + TypeScript + MUI の環境が整い、Robotoフォントも正しく実装されました!

📌次回予告

次回は、この環境を使って複数ページを作成する方法(React Router)を紹介します。お楽しみに!

2024年12月15日日曜日

C#をはじめよう!:Visual Studioインストール

 C#を始めるには、Microsoftが無料で提供する高機能なIDE、Visual Studio Community Editionを使うのがおすすめです。この記事では、Visual Studio Community Editionのインストール手順を解説します。

Visual Studio Community Editionのインストール

1. Visual Studioのダウンロード

  1. Visual Studioのオフィシャルサイト へアクセスします。

  2. トップページの「Download Visual Studio」ボタンから、Community Editionを選択します。

2. Visual Studio Installerの起動

  1. ダウンロードしたファイルをクリックして、Visual Studio Installerを起動します。

  2. Installerが起動したら、インストールするロールを選択します。

3. C#開発環境の選択

  1. Installerで「.NET desktop development」のワークロードを選択します。

  2. チェックボックスがある場合は、そのまま進めます。

  3. 「Install」ボタンをクリックして、インストールを始めます。

4. Visual Studioの起動

  1. インストール完了後、Visual Studioを起動します。

  2. 初回起動時には、テーマを選択します。例えば、ダークモードやライトモードが選べます。

  3. 「Create a new project」を選択し、プロジェクト作成の準備をします。

おわりに

これでVisual Studio Community Editionのインストールは完了です。次の記事では、初めてのC#プログラムを作成する手順を解説します。ぜひ、Visual Studioを使ってC#の開発を楽しんでください!

【MySQL 8.4.3 LTS】WindowsでZip Archiveからインストールする方法

✅はじめに

こんにちは!今回は、MySQL 8.4.3 LTSをWindowsにインストールする際に、Zip Archiveを使用する手順を解説します。この方法は、軽量で柔軟なセットアップが可能なため、インストールディレクトリを自由に指定したい場合や、複数のMySQLバージョンを管理したい場合に適しています。




📦1. MySQL 8.4.3 LTSのZip Archiveをダウンロード

  1. MySQL公式サイトにアクセスします。
  2. 「MySQL Community (GPL) Downloads »」を選択します。
  3. 「MySQL Community Server」をクリックし、ページ下部の「Looking for previous GA versions?」を選択してバージョン一覧を表示します。
  4. OSとして「Microsoft Windows」を選択し、Windows (x86, 64-bit), ZIP Archiveをダウンロードします。
  5. 「No thanks, just start my download」をクリックしてダウンロードを開始します。



🗂2. ダウンロードしたZipファイルの解凍

  1. ダウンロードした mysql-8.4.3-winx64.zip を右クリックして、解凍します。
  2. 解凍先は自由ですが、推奨ディレクトリとして以下のような場所を使用します:
    C:\mysql



⚙️3. MySQLの初期設定

  1. my.iniファイルの作成
    解凍先のフォルダに移動し、以下の内容で my.ini ファイルを作成します:


[mysqld]
# 基本設定
basedir=C:/mysql datadir=C:/mysql/data
port=3306
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

[client]
port=3306
  • basedir と datadir は解凍先に応じて変更してください。
  • datadir フォルダはこの後に作成します。
  1. データディレクトリの作成
    C:\mysql フォルダ内に新しく data フォルダを作成します。
  2. 初期化コマンドの実行
    コマンドプロンプトを管理者権限で開き、次のコマンドを実行してデータディレクトリを初期化します:

cd C:\mysql\bin mysqld --initialize --console
  • 初期化が成功すると、一時的なrootパスワードが表示されます(例:A temporary password is generated for root@localhost: <パスワード>)。このパスワードをメモしておきます。



🚀4. MySQLを起動する

  1. MySQLサーバーの起動
    初期化が完了したら、次のコマンドを実行してMySQLサーバーを起動します:

mysqld
  • サーバーはバックグラウンドで実行され、3306 ポートで待機します。
  1. MySQLサーバーの停止方法
    別のコマンドプロンプトを開き、次のコマンドを使用してサーバーを停止できます:

mysqladmin -u root -p shutdown



🔐5. MySQLへのログインと初期設定

  1. MySQLへのログイン
    別のコマンドプロンプトを開き、次のコマンドを実行します:

mysql -u root -p 
  • 一時的なパスワードを入力すると、MySQLプロンプトにログインできます。
  1. rootパスワードの変更
    セキュリティ向上のため、rootアカウントのパスワードを変更します:

ALTER USER 'root'@'localhost' IDENTIFIED BY '新しいパスワード';
  1. 設定の確認
    以下のコマンドを実行して、MySQLが正常に動作していることを確認します:

SELECT VERSION();



🖥6. MySQLをWindowsサービスとして登録(オプション)

Windowsの起動時に自動的にMySQLを起動させる場合、サービスとして登録します。

  1. サービス登録コマンド
    次のコマンドを実行してサービスを登録します:

mysqld --install MySQL
  1. サービスの起動
    サービスを起動するには、以下のコマンドを実行します:

net start MySQL
  1. サービスの停止
    サービスを停止する場合は、以下のコマンドを実行します:

net stop MySQL



💡7. 注意点と補足

  • セキュリティ強化
    必要に応じてユーザー権限を設定し、rootアカウント以外のユーザーを作成してください。
  • 環境変数の設定
    コマンドを簡略化するために、C:\mysql\bin を環境変数 PATH に追加することをおすすめします。



🔚まとめ

この記事では、MySQL 8.4.3 LTSをWindows環境にZip Archiveを使用してインストールする手順を解説しました。インストールが完了したら、必要に応じてMySQL WorkbenchなどのGUIツールを利用してデータベースを管理することも可能です。

この記事が参考になれば幸いです!質問や不明点があればコメントでお知らせください。

2022年6月7日火曜日

Xcodeのインストールがなかなか終わらない

 Xcodeをアップデートしているときに、なかなかインストールが終わらないとか、何か問題が起きて止まってる?みたいなことがあると思いますが、ただ単純に時間が掛かっている場合があるようです。その場合には、インストールログをtailで見て動いているか確認できます。

ちなみに、アップデートが完了するまでに約1時間...やる気が削がれますw

tail -f /var/log/install.log

2021年11月12日金曜日

Vue.jsでAvoid mutating a prop directly since the value ... が発生した場合の対応メモ

 Vue.jsで「Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: xxxx」というワーニングが出たので、以下のような対応をして回避しました。


発生原因

親コンポーネントから渡すデータを、子コンポーネント側で変更しようとしていたため出たワーニングと思われます。
エラーメッセージをGoogle翻訳で訳してみると「親コンポーネントが再レンダリングされるたびに上書きされるため、Propを直接変更することは避けてください。...」らしいです。

対応方法

子コンポーネントで値を代入している箇所があったので、該当箇所を修正しました。その後ワーニングは出なくなりました。

その他情報

vue 2.6.12
typescript 3.9.7

2021年11月10日水曜日

WSL2(Windows Subsystem for Linux2)でnpm installやvue createなどが遅い件

 WSL2(Windows Subsystem for Linux2)でnpm installやvue createなどのコマンド操作が遅い

本日2本目のブログ投稿です^^;つい先日Surface Pro 8を購入して、vue.jsの環境を構築しようとWSL2を使ってみたのですが、npmやvue createといったコマンド操作が非常に遅くて困ってました。結局解決できず、WSLで設定しなおすことにしたので、その手順をメモ次いでに記載します。
※今後解決できれば、それもブログに書きたいと思っています。

作業手順

(1)Windows PowerShellを起動する。

(2)コマンド「wsl --list --verbose」と入力し、現在の状態を確認する。
  NAME            STATE           VERSION
* Ubuntu-20.04    Stopped         2

(3)コマンド「wsl --set-version Ubuntu-20.04 1」と入力して、実行環境をWSL2からWSLに切り替える。数分かかるのでしばらく待機する。

(4)終わったら、再度(2)のコマンドを実行して、状態を確認する。
  NAME            STATE           VERSION
* Ubuntu-20.04    Stopped         1

WSL2からWSLに切り替えたことにより、npm installやvue createのコマンド操作の時間が改善されました。すごい早いわけではないですが...
WSL2だと、Windowsのファイルシステム(/mnt/c/xxxx)を参照すると非常に遅いといった書き込みなど多数見かけましたが、私はLinux上のhomeディレクトリで作業していたので、関係ないよなぁと思いつつ、たぶんネットワークのI/Oが遅いのかなぁと思って、ネットを徘徊していましたが、遅い理由が見つけられませんでした。

しばらくはWSLで様子をみつつ、WSL2のほうもたまにネットで調べてみようと思っています。

iPhoneのMagSafeバッテリーパックについて

iPhoneの背面に取り付けるMagSafeバッテリーパックを購入!

前回の投稿からだいぶ間が空いてしまいましたが、久しぶりのブログ投稿です^^;1年ほど前からコロナ禍で在宅勤務が増えて、自分の勉強を兼ねてブログを書こうと思っていましたが、やっと書く気になりましたw
基本的にはプログラミングネタを書くのですが、最近買ったガジェットとかも紹介してみようと思います。
※アフィリエイトやってないので、自由気ままに書きます。

購入の動機

iPhone12 Pro Maxを使用しているのですが、MagSafeで充電できるモバイルバッテリーがあったら便利だなぁと思い購入しました。

結論

先ほど述べた通り、アフィリエイトではないので自由な感想を述べますが、率直に申し上げてコスパが悪く、期待していたレベルのものではないなぁと思っています。完全に私の事前調査不足です。この製品を有効に活用するためには、製品の特長を理解して使うようにする必要があると思います。とはいえ、せっかく買ったので、外出時には積極的に装着して使うようにしています。
以下、良い点、悪い点、総評など好き勝手に述べていきます。

良い点

  1. アップル純正のモバイルバッテリーなので、安心して使用できる。アップルの純正ケースをつけていても使用することができ、デザインも良いと思っています。
  2. iPhoneにMagSafeで取り付け・取り外しができるので楽です。ただ、MagSafeモバイルバッテリーパック自体はライトニングケーブルで接続して充電する必要があります。
  3. モバイルバッテリーのほかに、MagSafe充電器のような使い方もできる。ただ、充電スピードまでは確認してません。

悪い点

  1. MagSafeバッテリーパックが満充電の状態でも、iPhoneを完全に充電することはできない。補助バッテリーみたいな感じ?で、iPhone本体の電池の減りを緩やかにするイメージ。
  2. コストパフォーマンスが悪い。MagSafeバッテリーパックの価格で、モバイルバッテリーがいくつ買えるだろうか...
  3. MagSafeバッテリーパック本体が滑りやすく、iPhoneに装着すると重みも増すので、落としそうで不安になる。
  4. 厚みがそこそこあるので、ズボンのポケットとかに入れるのは厳しい。重みも増すので、ちゃんとベルトとかしないとズボンが下がってくる。カバンにiPhoneしまうと、suica使いたいときに不便なので、そういう時は外してポケットに入れてます。

総評

外出先でiPhoneの電池残量が少なくなった時に、MagSafeバッテリーパックで充電しよう!みたいな使い方を想定している方は、この製品はやめたほうが良いと思います。MagSafeバッテリーパックのバッテリー容量は1460mAhで、iPhone12 Pro Maxのバッテリー容量は3687mAhです。MagSafeバッテリーパックはiPhone本体の半分以下となっているようです。
使い方としては、iPhone本体のバッテリー容量を増やすようなイメージで、MagSafeバッテリーパックを装着すると、iPhone本体の電池の減りが緩やかになります。

お値段は、アップル公式で11,800円(税込)しますが、純正品で、安心して使えて、iPhoneのバッテリー消費を緩やかにして、さらにデザインがとても好きって人は買ってもよいのかもしれません。
単純に外出先でiPhoneを充電したいという方は、ほかのモバイルバッテリーを検討することをお勧めします。

2018年2月17日土曜日

Windows10をアップデートしたらインターネットに接続できなくなった(バージョン1709 Fall Creators Update)

Windows10で突如インターネット接続不可に...

さて、2018年も早いもので2月となり、確定申告の季節がやってきました!私は個人事業主なので、確定申告の準備のためPCを起動、弥生の青色申告オンラインを使用しようとしたら、まさかのインターネットに繋がらないというトラブルに見舞われました...

同様にお困りの方もいるかもしれないので、こちらに私が対応した方法を記載します。

Windows10のFall Creators Update(バージョン1709)が原因?

Windowsを起動したら、例のごとくWindows Updateが自動で走り、アップデート完了後にWindowsにログインしたらインターネットに繋がらないトラブルが発生しました。
インターネットに繋がらない問題のほかに、なぜかログインを2回行わせようとする不可解の動きもありました。PCがインターネットに繋がらないので、iPhoneでググって調べながら再起動やら、シャットダウンやら、ネットワークの再設定を試しましたが解決せず。
結局、Windowsを前のバージョンに戻して解決することにしました。

Windows10で前のバージョンへの戻し方

戻し方は、他のサイトに詳しくありますが、概ね以下の手順を踏むことで戻すことができます。
  1. 画面左下の「スタートボタン」をクリック
  2. 「設定」ボタンをクリック
  3. Windowsの設定画面の「更新とセキュリティ」をクリック
  4. 「回復」をクリック
  5. 前のバージョンのWindows10に戻すにある「開始する」ボタンをクリック
  6. ウィザードっぽいのが立ち上がるので、あとは手順通りに進めるだけ。途中、「更新プログラムをチェックしますか?」とか聞かれますが、インターネットに繋がらないので「チェックしない」を選べばOK。
ただし、この手順ではアップデートしてから10日以内でないとできないらしい。

復元後のバージョンは1703

無事に前のバージョンへの復元が終わりログインすると、先ほどのログインを2回行わせる不可解な動きは解消され、インターネットへも問題なく接続できました。
これで、ようやく確定申告に向けて作業ができるようになりました!

2017年6月29日木曜日

Excel VBAでMySQLからデータを取得する

Excel VBAでMySQLからデータを取得して表示する

久しぶりにExcel VBAに触れる機会があったので、サンプルプログラムを載せます。久しぶりすぎていろいろダメなところがあるかと思いますがご愛嬌ということで^^;

環境

 本投稿のサンプルプログラムは、以下の環境で作成しております。
  • Windows10 Pro
  • Microsoft Office 2013
  • MySQL 5.7.18

事前条件

MySQLのインストールやらは今回省略しております。よろしければ、以下のブログを参考にしていただければと思います。

MySQL側に以下のテーブルを準備する

エリアマスタ(m_area)
  1. エリアID(id)
  2. エリア名(name)
都道府県マスタ(m_pref)
  1. 都道府県ID(id)
  2. エリアID(area_id) ※エリアマスタとのリレーション
  3. 都道府県名(name)

ODBCデータソースアドミニストレータのユーザDSNに登録する

以下は参考例です。環境に応じて読み替えてください。ドライバは「MySQL ODBC 5.3 ANSI Driver」です。DSNを設定する際には「Connector/ODBC」をインストールする必要があります。

  • Data Source Name = "任意の名称" ※例:MySQL Database
  • Descripiton = "未入力"
  • TCP/IP Server = "localhost"
  • Port = "3306"
  • User = "root"
  • Password = "未入力"


参照設定(Microsoft ActivX Data Objects 6.1 Library)

参照設定をする際に、2.xや6.xなどのバージョンがありますが、特に古い環境で使用する予定がなければ最新のものを参照設定してあげればよいと思います。

クラスモジュール作成

データベースからの取得結果を受け取るクラスモジュールを作成します。この辺りの実装方法は好みなので、別に無理に作らなくてもよいです。
init()はJavaで言うとコンストラクタっぽいことをやるために実装しています。VBAでもコンストラクタはあるらしいのですが、引数を設定できないようなので、以下のようにしています。
データベースから取得したレコードをこちらのオブジェクトに設定して、Collection配列に格納しています。

オブジェクト名:AreaModel

Option Explicit

Private mAreaId As Integer
Private mAreaName As String
Private mPrefId As Integer
Private mPrefName As String

Public Function init(areaId As Integer, areaName As String, prefId As Integer, prefName As String)
    mAreaId = areaId
    mAreaName = areaName
    mPrefId = prefId
    mPrefName = prefName
End Function

Public Property Get getAreaId() As Integer
    getAreaId = mAreaId
End Property

Public Property Get getAreaName() As String
    getAreaName = mAreaName
End Property

Public Property Get getPrefId() As Integer
    getPrefId = mPrefId
End Property

Public Property Get getPrefName() As String
    getPrefName = mPrefName
End Property

標準モジュール作成

MySQLへの接続、SQLの実行、セルに値を設定して表示する、といった一連の処理を作成します。connectionStringやSQL文、セルに値を設定する部分はプログラムの見た目が悪くなるので、別functionに委譲しています。

オブジェクト名:M_DB

Option Explicit

Sub selectArea()
    Dim conn As New ADODB.connection
    conn.CursorLocation = adUseClient
    conn.connectionString = createConnectionString
    conn.Open
   
    Dim rs As ADODB.recordSet
    Set rs = conn.Execute(areaSelectSql)
   
    ' DBからの取得結果を配列に格納
    Dim areaList As New Collection
    Dim area As AreaModel
    Do While rs.EOF = False
        Set area = New AreaModel
        area.init rs.Fields(0), rs.Fields(1), rs.Fields(2), rs.Fields(3)
        areaList.Add area
        rs.MoveNext
    Loop
   
    ' DBから取得したデータをセルに配置
    showCells areaList
   
    ' 後始末
    rs.Close
    Set rs = Nothing
    conn.Close
    Set conn = Nothing
End Sub

Private Function createConnectionString()
    Dim connectionString As String
    connectionString = "Driver={MySQL ODBC 5.3 ANSI Driver};" _
        & " Server=localhost;" _
        & " Database=test201706;" _
        & " Uid=root;" _
        & " Pwd=;"
    createConnectionString = connectionString
End Function

Private Function areaSelectSql() As String
    Dim sql As String
    sql = "SELECT " _
        & "a.id as area_id " _
        & ",a.name as area_name " _
        & ",p.id as pref_id " _
        & ",p.name as pref_name " _
        & "FROM " _
        & "test201706.m_area as a " _
        & "inner join test201706.m_pref as p on a.id = p.area_id"
    areaSelectSql = sql
End Function

Private Function showCells(areaList As Collection)
    ' 先頭行
    Worksheets("Sheet1").Cells(1, 1).Value = "エリアID"
    Worksheets("Sheet1").Cells(1, 2).Value = "エリア名"
    Worksheets("Sheet1").Cells(1, 3).Value = "都道府県ID"
    Worksheets("Sheet1").Cells(1, 4).Value = "都道府県名"
   
    ' データ部
    Dim rowIdx As Integer
    rowIdx = 2
    Dim area As Variant
    For Each area In areaList
        Worksheets("Sheet1").Cells(rowIdx, 1).Value = area.getAreaId
        Worksheets("Sheet1").Cells(rowIdx, 2).Value = area.getAreaName
        Worksheets("Sheet1").Cells(rowIdx, 3).Value = area.getPrefId
        Worksheets("Sheet1").Cells(rowIdx, 4).Value = area.getPrefName
        rowIdx = rowIdx + 1
    Next
End Function

2017年5月26日金曜日

Windows10 ProでHyper-Vでubuntu16.04をセットアップ

大変ご無沙汰しすぎて、久しぶりの投稿です!
最近、我が家のPC老朽化に伴い、Thinkpad T470sを購入しました。Macのようなおしゃれな感じはないですが、仕事で使う道具としてはシンプルでとても満足しております!
それはさておき、今回購入したマシンは仕事で使用するために購入したので、OSもWindows10 Proにしました。Windows10 ProにはHyper-Vという仮想マシンが標準で使えるので、さっそくubuntu16.04をインストールしてみました。

Windows10 ProのHyper-Vにubuntu16.04をセットアップする大まかな作業手順


作業の大まかな流れは以下の通りです。作業を進めていくうえで、特に難しい点はなかったですが、端末によってはHyper-Vをセットアップする際にBIOSの設定変更が必要となる場合がありそうです。私のマシンもBIOSで設定を変えました。
  1. Hyper-Vのセットアップ
  2. ubuntuのisoイメージをダウンロード
  3. 仮想スイッチの作成
  4. 仮想マシンの作成とインストール

Hyper-Vのセットアップ


標準で使用できるとはいえ、初期状態では使える状態になっていないのでセットアップを行います。
コントロールパネル→プログラム→プログラムと機能を開きます。画面左側に「Windowsの機能の有効化または無効化」があるのでクリックします。Hyper-Vを選択状態にしてOKボタンをクリックします。
もしここで、Hyper-Vプラットフォームが選択できない状態の場合は、BIOSの設定を変更する必要があります。BIOSを起動して以下の項目を変更します。
Advanced → CPU Configuration → Execute Disable Bit → [Enabled]
Advanced → CPU Configuration → Intel(R) VirtualizationTechnology → [Enabled]
BIOSの変更が終わったら設定を保存して、再び上記の作業を行います。

ubuntuのisoイメージをダウンロード


以下のサイトからダウンロードします。このファイルを後で使用するので、適当な場所に保存します。
http://www.ubuntulinux.jp/download/ja-remix

仮想スイッチの作成


「Hyper-V マネージャー」を起動します。画面右側の「仮想スイッチ マネージャー」をクリックします。

仮想スイッチを新規作成します。「外部」を選択して「仮想スイッチの作成」ボタンをクリックします。その後、適当な名前を付けてOKボタンをクリックします。




仮想マシンの作成とインストール


仮想マシンを新規に作成して、ubuntuをインストールしていきます。Hyper-Vマネージャーの画面右側にある「新規」「仮想マシン」をクリックします。インストールはウィザードに従って進めていきます。


とりあえず「次へ」をクリックします。


仮想マシンの名前を入力します。任意のフォルダにしたい場合はフォルダも指定します。


第1世代か第2世代かを選択します。今回は第2世代を選択します。この辺りが気になる方は以下のサイトに説明が載っています。
https://technet.microsoft.com/ja-jp/library/dn282285.aspx


メモリの割り当てサイズを決めます。私のマシンではメモリに余裕があるので2GB割り当てました。必要に応じてサイズを決めてください。


前の作業で作成した仮想スイッチを選択します。


仮想ハードディスクの設定を行います。この手順通り進めた場合、仮想ハードディスクは作成されていないと思いますので、新規作成します。割り当てサイズはデフォルト値だと大きいと思いますので変更します。ひとまず30GB割り当てます。


前の作業でダウンロードしたisoイメージファイルを指定します。


最後に内容を確認して「完了」ボタンをクリックするとセットアップが行われます。


セットアップが完了したら仮想マシンを起動します。仮想マシンを起動する前に「セキュアブートを有効にする」にチェックが入っていると起動しないため、チェックを外します。作成した仮想マシンを右クリックして「設定」をクリックします。セキュアブートを有効にするのチェックボックスを外してOKボタンをクリックします。

作成した仮想マシンをダブルクリックして仮想マシンを起動します。ツールバーに電源ボタンがあるので、クリックすると仮想マシンが起動され、ubuntuのセットアップへと進みます。


この後の作業はubuntuのインストール作業となり、Hyper-V独自の作業ではないため割愛します。ウィザードの通り進めていけばubuntuのセットアップも問題なくできると思います。


2017年1月3日火曜日

Windows10にMySQL5.7をインストール

Windows10にMySQL5.7(ZIP Archive)をインストール

手元にWindows10端末が手に入ったので、さっそくMySQLをインストールしてみました。本記事はMySQL5.7をインストールした際のメモです。インストール方法についてはZIP Archiveで行います。

(1)MySQL Community Serverをダウンロード

ダウンロードページで「Windows (x86, 64-bit), ZIP Archive」をダウンロードします。

(2)ダウンロードしたファイルを解凍して配置

ダウンロードしファイルを解凍して配置します。本記事では作成場所を「C:\server\mysql\mysql-5.7.17-winx64\」とします。

(3)データフォルダの作成

データフォルダを作成します。本記事では作成場所を「C:\server\mysql\mysql-5.7.17-winx64\data\」とします。

(4)my.iniファイルの作成

my.iniファイルを作成します。本記事では作成場所を「C:\server\mysql\mysql-5.7.17-winx64\my.ini」としました。my.iniファイルの記載内容については、以下を参考にしてください。また、パスを記載する際には¥は使えないので、スラッシュを使います。
[mysqld]セクションの中には、MySQLサーバの動作に関する記述です。
[mysql]セクションには、mysql.exe(クライアントツール)の動作に関する記述です。

[mysqld]
basedir=c:/server/mysql/mysql-5.7.17-winx64/
datadir=c:/server/mysql/mysql-5.7.17-winx64/data/
character-set-server=utf8
[mysql]
default-character-set=utf8

(5)コマンドを使って初期化

管理者権限でコマンドプロンプトを起動します。本記事ではmysqldが「c:\server\mysql\mysql-5.7.17-winx64\bin」の中に入っているため、フォルダを移動します。そして、以下のコマンドを入力し、実行します。

>mysqld --initialize-insecure --console

すると、以下のようにコマンドプロンプトに表示されます。

2016-12-30T02:29:20.484733Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2016-12-30T02:29:21.113727Z 0 [Warning] InnoDB: New log files created, LSN=45790
2016-12-30T02:29:21.241187Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
2016-12-30T02:29:21.339550Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: c57fd5a5-ce37-11e6-beb3-f0d5bf000ae0.
2016-12-30T02:29:21.356860Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
2016-12-30T02:29:21.366678Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.

もし、以下のような内容がコマンドプロンプトに表示された場合、dataフォルダに何か入っている可能性があるため、dataフォルダの中身を空にします。

2016-12-30T02:28:57.458744Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2016-12-30T02:28:57.460749Z 0 [ERROR] --initialize specified but the data directory has files in it. Aborting.
2016-12-30T02:28:57.461752Z 0 [ERROR] Aborting

(6)MySQLを開始

コマンドプロンプトでMySQLを開始します。本記事では、サービスに登録せずに、コマンドからMySQLを起動します。(5)と同じく、mysqldが入っているフォルダまで移動し、以下のコマンドを入力します。

> mysqld --console

(7)MySQLに接続

コマンドプロンプトを起動し、以下のコマンドを入力します。(5)と同じくmysqlが入っているフォルダまで移動します。

>mysql -u root

(8)簡単な動作確認

「show databases;」などのコマンドを入力して、データベース一覧が表示されればインストールがうまくいっていると思われます。
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.10 sec)

※以下のサイトを参考にしました。あわせてご覧ください。

2016年3月19日土曜日

CentOS6.7にPHP環境をインストール

最近仕事でPHPを...

 最近の案件で、PHPを使う必要が出てきたので、慌てて(?)勉強しています。まずは私の自宅のサブマシン(CentOS)に開発環境を構築していきます。

yumでhttpdとphpをインストール


「端末」を起動してrootに変更して、以下のコマンドを実行します。

# yum install httpd php

途中「これでいいですか? [y/N]と表示されるので[y]を入力します。これでインストールが完了します。
その後、apacheを起動します。起動中かどうかは以下のコマンドで確認できます。

# /etc/init.d/httpd status
http (pid xxxx) を実行中...


と表示されていれば、apacheが起動されています。
起動されていない場合は、以下のコマンドでapacheを起動します。

# /etc/init.d/httpd start

ちなみに、停止は以下のコマンドで行えます。
# /etc/init.d/httpd stop


PHPの動作確認


次にPHPの動作確認を行います。動作確認は以下のコマンドで行います。

# php -v
PHP 5.3.3 (cli) (built: Feb 9 2016 10:21:34)
Copyright (c) 1997-2010 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies

次にApache経由でPHPが動作することを確認します。動作確認用にphpinfo()をphpinfo.phpファイルに記述します。ファイルを作成する場所は「/var/www/html」の配下です。
作成後にブラウザにURL「http://localhost/phpinfo.php」を入力して、PHP INFOが表示されればOKです。

※別のPCからアクセスさせる場合は80番ポートを開放します。デフォルトではアクセスできません。80番ポートの開放は、iptablesを編集します。手順は以下の通りです。

(1)iptablesファイルをバックアップします。名前は適当に決めてください。

# cp /etc/sysconfig/iptables /etc/sysconfig/iptables.org.yyyymmdd

(2)viでiptablesを編集します。
# vi /etc/sysconfig/iptables

-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icml-host-prohibited


念のためdiffで差分を確認します。
# diff iptables.org.yyyymmdd iptables

10a11
> -A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT


(3)ファイアウォールの設定を反映します。
# service iptables restart

iptables: チェインをポリシー ACCEPT へ設定中filter         [  OK  ]
iptables: ファイアウォールルールを消去中:                  [  OK  ]
iptables: モジュールを取り外し中:                          [  OK  ]
iptables: ファイアウォールルールを適用中:                  [  OK  ]


(4)別のPCブラウザのURLに「http://端末のIPアドレス/phpinfo.php」を入力します。これで別PCでもPHP INFOが表示されればOKです。