KeihakuOh / Mini-Microservices-App

0 stars 0 forks source link

section11_memo #12

Open KeihakuOh opened 1 month ago

KeihakuOh commented 1 month ago

CMD ["npm", "run", "dev"] 概要: この行は、コンテナが起動されたときに実行されるデフォルトのコマンドを指定 この場合はnpm run dev コマンドを実行

KeihakuOh commented 1 month ago

next.jsのPages router

pages/ ├── index.js // ルートページ: / ├── about.js // Aboutページ: /about └── blog/ └── [slug].js // 動的ルート: /blog/[slug]

app/blog/[slug]/page.js:

export default function BlogPost({ params }) {
  const { slug } = params;

  return <h1>Blog Post: {slug}</h1>;
}

next.jsのApp router

app/ ├── page.js // ルートページ: / ├── about/ │ └── page.js // Aboutページ: /about └── blog/ └── [slug]/ └── page.js // 動的ルート: /blog/[slug]

pages/blog/[slug].js:

import { useRouter } from 'next/router';

export default function BlogPost() {
  const router = useRouter();
  const { slug } = router.query;

  return <h1>Blog Post: {slug}</h1>;
}

App Router は、Next.js の新しい機能(React Server Components や Streaming SSR など)を完全にサポートしており、より高速で効率的なレンダリングができる

基本はディレクトリをちゃんとやれば設定せずにrouterを使える、 両方を同時に使用する場合: Next.js 13以降では、pagesディレクトリとappディレクトリを同時に使用することも可能。ただし、同じパスが両方に存在する場合、appディレクトリのルートが優先される。

KeihakuOh commented 1 month ago
next.config.js:
module.exports = {
  webpack: (config) => {
    config.watchOptions.poll = 300;
    return config;
  },
};

このファイルは"next"のコマンドにより実行される module.exportsは、Node.jsのモジュールシステムの一部である(node.jsがなければならない)  これはNext.jsのビルドプロセスでインポートする。 ちなみにこれによって300ミリ秒ごとにファイルシステムをチェックするようになる

KeihakuOh commented 1 month ago

_app.jsファイル:next.jsにおいてコンポネートは表示する前にこの_app.jsファイル通してから表示する。→ 例えばhome.jsを表示したい時の順番は_app.jsに行き、その中で_app.jsのpropsを実行、home.jsは_app.jsのコンポネートとして呼ばれる。home.js内の変数にpropsの変数の値を代入

実際の使用例:

import 'bootstrap/dist/css/bootstrap.css';

function MyApp({ Component, pageProps }) {
  // `Component`が現在表示されるべきページコンポーネント
  // `pageProps`が各ページに渡されるプロパティ
  return <Component {...pageProps} />;
}

export default MyApp;
// pages/user.js
const UserPage = ({ user }) => {
  return (
    <div>
      <h1>User Information</h1>
      <p>Name: {user.name}</p>
      <p>Email: {user.email}</p>
    </div>
  );
};

export default UserPage;

// pagePropsを提供する関数
export async function getServerSideProps() {
  // サーバーサイドでAPIからユーザーデータを取得
  const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
  const user = await res.json();

  // propsとしてユーザーデータを返す
  return { props: { user } };
}

流れ:getServerSidePropsから返されたprops(ユーザーデータ)は、UserPageコンポーネントに渡される → UserPageコンポーネントは、pages/_app.jsのカスタムAppコンポーネントによってラップされて表示される。 importしなくてもnext.jsが勝手にわかる

KeihakuOh commented 1 month ago

git push --set-upstream origin feature/integrate-react-app これよって次からはgit push だけでいける

KeihakuOh commented 1 month ago
  event.preventDefault();

    const response = await axios.post('/api/users/signup', {
      email,
      password,
    });

    console.log(response.data);
  };

onSubmit関数全体は、ユーザーがフォームを送信する際にクライアントサイド(ブラウザ)で実行される。

eventは、フォームが送信された時にトリガーされるsubmitイベントを指す。このイベントオブジェクトには、イベントに関連する情報が含まれています。例えば、イベントがどこで発生したか(targetプロパティ)、イベントのタイプ(typeプロパティ)、そしてpreventDefaultやstopPropagationなどのメソッドを提供する。

submitイベントが発生すると、通常はブラウザが以下のようなデフォルトの動作を行う:1.フォームの内容をサーバーに送信。2.現在のページがリロードされる。preventDefaultはこれを止める用

デフォルトの送信するエンドポイント: 1.

actionが指定されている場合:
<form action="/submit" method="POST">
  <input type="text" name="username" />
  <input type="password" name="password" />
  <button type="submit">Sign In</button>
</form>
この場合、フォームが送信されると、/submitエンドポイントにPOSTリクエストが送信される。

2.

actionが指定されていない場合:
<form method="POST">
  <input type="text" name="username" />
  <input type="password" name="password" />
  <button type="submit">Sign In</button>
</form>
この場合、フォームが現在のページに対して送信される。例えば、ページのURLがhttps://example.com/loginであれば、https://example.com/loginにデータが送信される。
KeihakuOh commented 1 month ago

err.response.dataは、axiosがHTTPリクエストのエラーハンドリングの際に提供するオブジェクトの一部。具体的には、axiosがサーバーからのレスポンスを処理する際に、responseオブジェクトを作成し、その中にdataプロパティを含めている。

KeihakuOh commented 1 month ago

hooks: 特定の機能をコンポーネントに「フック」する(追加する)ための関数

KeihakuOh commented 1 month ago
ファイル1:
import { useState } from 'react';
import axios from 'axios';
import useRequest from '../../hooks/use-request';

export default () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const { doRequest, errors } = useRequest({
    url: '/api/users/signup',
    method: 'post',
    body: {
      email,
      password
    }
  });

  const onSubmit = async event => {
    event.preventDefault();

    doRequest();
  };

  return (
    <form onSubmit={onSubmit}>
      <h1>Sign Up</h1>
      <div className="form-group">
        <label>Email Address</label>
        <input
          value={email}
          onChange={e => setEmail(e.target.value)}
          className="form-control"
        />
      </div>
      <div className="form-group">
        <label>Password</label>
        <input
          value={password}
          onChange={e => setPassword(e.target.value)}
          type="password"
          className="form-control"
        />
      </div>
      {errors}
      <button className="btn btn-primary">Sign Up</button>
    </form>
  );
};
ファイル2:
import axios from 'axios';
import { useState } from 'react';

export default ({ url, method, body }) => {
  const [errors, setErrors] = useState(null);

  const doRequest = async () => {
    try {
      setErrors(null);
      const response = await axios[method](url, body);
      return response.data;
    } catch (err) {
      setErrors(
        <div className="alert alert-danger">
          <h4>Ooops....</h4>
          <ul className="my-0">
            {err.response.data.errors.map((err) => (
              <li key={err.message}>{err.message}</li>
            ))}
          </ul>
        </div>
      );
    }
  };

  return { doRequest, errors };
};

doRequest()→useStateのerrorsが値変わる→てReactの再レンダリング ページ全体が再ロードされるわけではなく、フォームとそのエラーメッセージが含まれる部分だけが更新される

KeihakuOh commented 1 month ago
const LandingPage = ({ color }) => {
  **_console.log('I am in the component', color);_**
  return <h1>Landing Page</h1>;
};

LandingPage.getInitialProps = () => {
  **_console.log('I am on the server!');_**

  return { color: 'red' };
};

export default LandingPage;

console.log('I am on the server!');はどこで表示について(getInitialPropsはどこで実行について): 1.画面遷移の場合はブラウザ(コンポネート内でgetリクエスト) 2.それ以外はサーバ(リンクをクリック、無理やりreload)

KeihakuOh commented 1 month ago

axios.get('/api/users/currentuser');について

ブラウザでの実行(クライアントサイド): 例えば、あなたのアプリケーションが https://example.com でホストされている場合、axios.get('/api/users/currentuser')は https://example.com/api/users/currentuser に対してリクエストを送信する

開発中にローカルでNext.jsアプリケーションを実行している場合、サーバーサイドでのリクエストは通常、http://localhost:3000 などのローカルホストに送られる。

KeihakuOh commented 1 month ago

kubectl get services -n ingress-nginx 特定の名前空間(この場合はingress-nginx)内のサービスをリスト表示

Kubernetesには、いくつかのデフォルトの名前空間が存在

yamlファイルで名前空間が指定されていない場合、これらのリソースはデフォルトでdefault名前空間に作成される。

KeihakuOh commented 1 month ago
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/use-regex: 'true'
spec:
  rules:
    - host: ticketing.dev
      http:
        paths:
          - path: /api/users/?(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: auth-srv
                port:
                  number: 3000
          - path: /?(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: client-srv
                port:
                  number: 3000

上は設定ファイルで、下のコード実際に送るのは内部DNS名のhttp://ingress-nginx-controller.ingress-nginx.svc.cluster.local/api/users/currentuser (サーバ側から行くならこれしかない)

const { data } = await axios.get(
  'http://ingress-nginx-controller.ingress-nginx.svc.cluster.local/api/users/currentuser',
  {
    headers: {
      Host: 'ticketing.dev',
    },
  }
);

ちなみに違うドメインに対して送信するとcookieは消える

KeihakuOh commented 1 month ago

Next.jsを使ってアプリケーションをローカルで起動する際、デフォルトではポート3000でサーバーが立ち上がる Next.jsサーバーを立ち上げただけでは、特定のページが自動的に表示されるわけではない。Next.jsが起動することで、サーバーがリクエストを待ち受ける状態になるが、実際にブラウザで特定のページを表示するには、ブラウザで対応するURLにアクセスする必要がある。

KeihakuOh commented 1 month ago

LandingPage.getInitialProps = async context => { const client = buildClient(context); const { data } = await client.get('/api/users/currentuser');

return data; }; contextオブジェクトは、Next.jsによって提供される引数である。プロパティにはreq, res, queryなどが含まれる。contextではなく、cccなどでも大丈夫。しかし引数を定義しない場合は使えない(async () =>)

KeihakuOh commented 1 month ago
AppComponent.getInitialProps = async appContext => {
  const client = buildClient(appContext.ctx);
  const { data } = await client.get('/api/users/currentuser');

  console.log(data);

  return data;
};

AppComponent.getInitialPropsの引数として渡されるオブジェクトで、アプリケーション全体のコンテキストに関する情報を含んでいる appContext.ctxは通常のページコンポーネントのgetInitialPropsで渡されるcontextオブジェクトに相当

KeihakuOh commented 1 month ago
const AppComponent = ({ Component, pageProps }) => {
  return (
    <div>
      <Component {...pageProps} />
    </div>
  );
};

AppComponent.getInitialProps = async appContext => {
  const client = buildClient(appContext.ctx);
  const { data } = await client.get('/api/users/currentuser');

  console.log(data);

  return data;
};

dataがpagePropsの一部になる。 <Component {...pageProps} />はpagePropsの中身がページコンポーネントにpropsとして展開される。つまりpagePropsの中の変数の値をコンポーネントの変数に代入する

例えばhome.jsを表示したい時の順番は_app.jsに行き、その中で_app.jsのpropsを実行、home.jsは_app.jsのコンポネートとして呼ばれる。home.js内の変数にpropsの変数の値を代入  →つまり、AppComponent.getInitialProps でhome.jsのpropsを実行する関数を呼ばないなら、home.jsのpropsを実行する関数は実際に実行されない.
ちなみにAppComponent.getInitialProps と言う関数が定義されなかったら、絶対home.jsのgetInitialPropsは実行する

KeihakuOh commented 4 weeks ago

k8sにおいてクラスタとノードの関係: クラスタは、Kubernetesが管理する一つの大きなシステムで、複数のノードから構成される。ノードは、クラスタを構成する個々のサーバーで、実際にアプリケーションが動作する場所。各ノードにはコンテナが実行されるポッドが配置される。つまり、ノードが多いと、それぞれのコンテナが使用できるCPUとかのリソースが多い

KeihakuOh commented 4 weeks ago

...dataを使うことで、dataオブジェクト内のプロパティが展開され、pagePropsと一緒に新しいオブジェクトの一部として返されることになる。

例:

const data = {
  user: "Alice",
  age: 30
};

 return {
    pageProps,
    ...data
  };

//上と同じ
return {
  pageProps,      
  user: "Alice",
  age: 30
};
KeihakuOh commented 4 weeks ago

BootstrapをNext.jsプロジェクト全体で利用する場合、_app.jsにインポートするだけで大丈夫。これにより、全てのページとコンポーネントでBootstrapのスタイルを利用できるようになる。

KeihakuOh commented 4 weeks ago
const links = [
  !currentUser && { label: 'Sign Up', href: '/auth/signup' },
  !currentUser && { label: 'Sign In', href: '/auth/signin' },
  currentUser && { label: 'Sign Out', href: '/auth/signout' },
]
  .filter((linkConfig) => linkConfig)
  .map(({ label, href }) => {
    return (
      <li key={href} className="nav-item">
        <Link className="nav-link" href={href}>
          {label}
        </Link>
      </li>
    );
  });

filterメソッドのコールバック関数が (linkConfig) => linkConfig !currentUser && { label: 'Sign Up', href: '/auth/signup' }などの結果がlinkConfigになる、=> linkConfigだから linkConfigによって判断する(返される値がtrueであればその要素を配列に残す)

KeihakuOh commented 4 weeks ago
const items = ['Apple', 'Banana', 'Cherry'];

const itemList = items.map((item, index) => (
  <li key={index}>{item}</li>
));

return <ul>{itemList}</ul>;

keyがあるだけで変更がある時に強制再レンダリングはしないけど、setStateなどによってする時は対応するkeyのところだけ再レンダリングする

KeihakuOh commented 4 weeks ago

next.jsのlink

import Link from 'next/link';

function Home() {
  return (
    <div>
      <Link href="/about">
        <a>Go to About Page</a>
      </Link>
    </div>
  );
}

export default Home;

htmlのaタグ

<a href="/about">Go to About Page</a>

Reactで通常のタグを使った場合、Next.jsのLinkコンポーネントと同じクライアントサイドルーティングやスムーズなユーザー体験を提供することはできない。タグではページ全体が再読み込みされ、状態がリセットされるため、ユーザー体験が劣る可能性がある

また、通常のタグを使用してリンクをクリックしたとき、ブラウザはサーバーにリクエストを送り、サーバーがそのリクエストに応じて適切なHTMLページを返す必要がある。このため、サーバー側でルーティングを処理するコードを記述する必要がある これとか

const express = require('express');
const app = express();

app.get('/about', (req, res) => {
  res.send('<h1>About Page</h1><p>This is the about page content.</p>');
});