プログラミング言語 技術

素人のフルスタック奮闘記:ログイン前のフロントエンド①

子供たちが高熱出したりしていて、家庭がてんやわんやで時間があいてしまいましたが、引き続きやっていきます。

Udemyのサイトを作っていくという話を前回したけど、そのままのものを作るつもりはなくて、かなり端折ったものにするつもり。
必要に応じてdeveloperツールを活用してプロの人達がどのように作っていくのかは分析するけど。

というわけで、まずは前回の記事で書いた流れの1番最初
 ①コードを綺麗にすることはあまり考えずまずは作る
というところからやっていこうと思う。

まずはログイン前のフロント部分だけをしこしこ作って、フロント作成の基礎中の基礎について勘所をお勉強。
そのあと、ログイン後のフロントを作ることで状態の管理などの勘所をお勉強。
そして、firebaseと連携してデータのやりとりを行うにあたっての勘所をお勉強。

と大きく3パートに分けてやっていく。
何か月かかるか分からないけど、時間を見つけてやっていこう。

作るもの

こんな感じのものを作っていく。
アイコンや画像はあんま本質ではないので、基本ChatGPTさんに作ってもらいました。

ルートページを作る

import { useState } from "react"
import { BrowserRouter, Routes, Route } from "react-router-dom";
import "./App.css";
import Menubar from "./components/Menubar/Menubar";
import Main from "./components/Main/Main";
import MyLearning from "./components/MyLearning/MyLearning";
import WishList from "./components/WishList/WishList";
import Cart from "./components/Cart/Cart";
import Notice from "./components/Notice/Notice";
import Profile from "./components/Profile/Profile";
import Footerbar from "./components/Footerbar/Footerbar";
import Login from "./components/Login/Login";
import Register from "./components/Register/Register";
import MainNoLogin from "./components/Main/MainNoLogin";

function App() {
  const [isLogin, setIsLogin] = useState(false);
  return (
    <BrowserRouter>
      <Menubar isLogin={isLogin}/>
      <Routes>
        {
          isLogin ?  <Route path="/" element={<Main />}></Route>
          :
          <Route path="/" element={<MainNoLogin />}></Route>
        }
        <Route path="/" element={<Main />}></Route>
        <Route path="/mylearning" element={<MyLearning />}></Route>
        <Route path="/wishlist" element={<WishList />}></Route>
        <Route path="/Cart" element={<Cart />}></Route>
        <Route path="/Notice" element={<Notice />}></Route>
        <Route path="/profile" element={<Profile />}></Route>
        <Route path="/login" element={<Login />}></Route>
        <Route path="/register" element={<Register />}></Route>
      </Routes>
      <Footerbar />
    </BrowserRouter>
  );
}

export default App;

App.tsxはデフォルトで作成されるファイル。
ここにコンポーネントたちを埋め込んで、画面遷移ができるように作成していく。

ここはただ単にルーティングをするだけの役割ページ。

MainNoLogin?あとでリファクタリングするからいいんだよ。

メニューバーを作っていく

TOPに添付したページの検索エリアなどがある一番上のコンポーネント部分を作る。

アイコンを使いたいのでfontawesomeをインストール。
https://docs.fontawesome.com/web/use-with/react/

npm i --save @fortawesome/fontawesome-svg-core
npm i --save @fortawesome/free-solid-svg-icons
npm i --save @fortawesome/free-regular-svg-icons
npm i --save @fortawesome/free-brands-svg-icons
npm i --save @fortawesome/react-fontawesome@latest

続いて、Menubar.tstを作成。

import { useState } from "react";
import { Link } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faHeart,
  faCartShopping,
  faBell,
  faUser,
} from "@fortawesome/free-solid-svg-icons";
import "./Menubar.css";
import SearchArea from "../SearchArea/SearchArea";

interface MenubarProps {
  isLogin: boolean;
}

const Menubar = ({ isLogin }: MenubarProps) => {
  return (
    <div className="MainMenuContainer">
      <div className="MenuContainer">
        <Link to="/">{<img src="/logo-udemy.svg" width={"90px"}></img>}</Link>
        {<SearchArea />}
        {!isLogin ? (
          <>
            <nav>Udemy Buisiness</nav>
            <nav>Udemyで教える</nav>
            <Link to="/Cart">{<FontAwesomeIcon icon={faCartShopping} />}</Link>
            <Link to="/Login">{<div className="login">ログイン</div>}</Link>
            <Link to="/Register">
              {<div className="register">新規登録</div>}
            </Link>
          </>
        ) : (
          <>
            <Link to="/mylearning">マイラーニング</Link>
            <Link to="/wishlist">{<FontAwesomeIcon icon={faHeart} />}</Link>
            <Link to="/Cart">{<FontAwesomeIcon icon={faCartShopping} />}</Link>
            <Link to="/Notice">{<FontAwesomeIcon icon={faBell} />}</Link>
            <Link to="/profile">{<FontAwesomeIcon icon={faUser} />}</Link>
          </>
        )}
      </div>
      <div className="header-bar"></div>
    </div>
  );
};

export default Menubar;

ここでのお勉強ポイントは2。

アイコンの使い方

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faHeart,
  faCartShopping,
  faBell,
  faUser,
} from "@fortawesome/free-solid-svg-icons";

~中略~

<Link to="/Cart">{<FontAwesomeIcon icon={faCartShopping} />}</Link>

各アイコンの名前の調べ方は以下の通り。
Fontawesomeアイコンのトップページに「Icon」メニューがあるので、それをクリック。

使いたいアイコンを検索してクリック。

「Individual Import」をクリックすると、コードの書き方が記載されている。

propsの渡し方

interface MenubarProps {
  isLogin: boolean;
}

interfaceとして個別に宣言し、型のように取り扱う。
使う場合に以下のようにするため、「型」という言葉を利用した。

const Menubar = ({ isLogin }: MenubarProps) => {

Menubaerのスタイルは以下の通り。

.MainMenuContainer{
  padding-right:8px;
  padding-left:8px;

}

.MenuContainer{
  width:100%;
  height:70px;
  display: flex;
  align-items: center;
  gap:20px;
}

.login{
  color:black;
  font-weight:bold;
  border: 0.5px solid black;
  padding: 10px 10px;
}

.register{
  background-color: black;
  color:white;
  font-weight:bold;
  border: 0.5px solid black;
  padding: 10px 10px;
  transition:all 0.3s;
}

.register:hover{
  background-color: #302f2f;
}

.MenuContainer a{
  text-decoration: none;
  color:black;
}

img{
  padding-left: 20px;
}

.header-bar{
  color: #0b0b0b;
  background-color: #dddddd;
  font-size: 30px;
  width: 100vw;
  height: 3px;
  box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.08),inset 0 4px 12px rgba(0, 0, 0, 0.08);
}

お勉強ポイントというか、CSS回りを作りこんでいて問題勃発・・・。

CSSは共通である

結構作りこんだところで発見したわけだけど、コンポーネント毎に独立していると思ったスタイルは、蓋を開けてみるとコンポーネントを超えて共有されていた。

例えば、aタグ。

リンクを下線を消したい部分とそのままにしたい部分があったとして、以下のように指定してしまうと、違うコンポーネントであってこのスタイルが適用されてしまう。

a{
  text-decoration: none;
  color:black;
}

自分のコードででは、現状divタグ1つにつきクラスは1つにしている。
それに対して、本家本元を確認すると細かくクラスが指定されている。

各コンポーネントに充てるクラスは事前に設計されていて、複数当てることによって制御をしているのだと理解した。

どういう単位で設計しているのかは要分析。少なくとも色とかフォントなんかは設計されているように見えた。

Menubarの中にポツンと宣言されている、SearchAreaは以下の通り。

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";

import "./SearchArea.css";

const SearchArea = () => {
  return (
    <div className="SearchContainer">
      <div className="ContainerItems">
        <input type="text" />
        <div className="dosearch">
          <FontAwesomeIcon icon={faMagnifyingGlass} />
        </div>
      </div>
    </div>
  );
};

export default SearchArea;
.SearchContainer{
  border:0.1px solid rgba(63, 63, 63, 0.939);
  border-radius: 30px;
  display:flex;
  align-items: center;
  padding:10px;
  flex-grow:1;
}

input {
  height: 30px;
  width: 100%;
  outline:none;
  border:none;
}

.dosearch{
  cursor: pointer;
  padding-right: 20px;
}

.SearchContainer .ContainerItems{
  display:flex;
  gap:10px;
  align-items: center;
  width: 100%;
}

ここのお勉強ポイントは1つですかね。

flex-growが便利

親要素がFlexコンテナの場合、flex-growプロパティを指定することが可能。
私が作成したコードでは、親要素は「MenuContainer」であり、Manuber.css側でdisplay: flexを指定している。

1つのflexアイテムにのみflex-growを指定しているが、別のアイテムにもflex-grow: 2のように指定すると、SearchAreaと他のアイテムの大きさの比率が1:2になる。

この設定により、ブラウザのリサイズに応じて各要素が動的にリサイズされるようになる。

以上が、Menubarの作成でした。

-プログラミング言語, 技術