Open KeihakuOh opened 1 month ago
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>;
}
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ディレクトリのルートが優先される。
next.config.js:
module.exports = {
webpack: (config) => {
config.watchOptions.poll = 300;
return config;
},
};
このファイルは"next"のコマンドにより実行される module.exportsは、Node.jsのモジュールシステムの一部である(node.jsがなければならない) これはNext.jsのビルドプロセスでインポートする。 ちなみにこれによって300ミリ秒ごとにファイルシステムをチェックするようになる
_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が勝手にわかる
git push --set-upstream origin feature/integrate-react-app これよって次からはgit push だけでいける
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にデータが送信される。
err.response.dataは、axiosがHTTPリクエストのエラーハンドリングの際に提供するオブジェクトの一部。具体的には、axiosがサーバーからのレスポンスを処理する際に、responseオブジェクトを作成し、その中にdataプロパティを含めている。
hooks: 特定の機能をコンポーネントに「フック」する(追加する)ための関数
ファイル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の再レンダリング ページ全体が再ロードされるわけではなく、フォームとそのエラーメッセージが含まれる部分だけが更新される
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)
ブラウザでの実行(クライアントサイド): 例えば、あなたのアプリケーションが https://example.com でホストされている場合、axios.get('/api/users/currentuser')は https://example.com/api/users/currentuser に対してリクエストを送信する
開発中にローカルでNext.jsアプリケーションを実行している場合、サーバーサイドでのリクエストは通常、http://localhost:3000 などのローカルホストに送られる。
kubectl get services -n ingress-nginx 特定の名前空間(この場合はingress-nginx)内のサービスをリスト表示
Kubernetesには、いくつかのデフォルトの名前空間が存在
yamlファイルで名前空間が指定されていない場合、これらのリソースはデフォルトでdefault名前空間に作成される。
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は消える
Next.jsを使ってアプリケーションをローカルで起動する際、デフォルトではポート3000でサーバーが立ち上がる Next.jsサーバーを立ち上げただけでは、特定のページが自動的に表示されるわけではない。Next.jsが起動することで、サーバーがリクエストを待ち受ける状態になるが、実際にブラウザで特定のページを表示するには、ブラウザで対応するURLにアクセスする必要がある。
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 () =>)
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オブジェクトに相当
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は実行する
k8sにおいてクラスタとノードの関係: クラスタは、Kubernetesが管理する一つの大きなシステムで、複数のノードから構成される。ノードは、クラスタを構成する個々のサーバーで、実際にアプリケーションが動作する場所。各ノードにはコンテナが実行されるポッドが配置される。つまり、ノードが多いと、それぞれのコンテナが使用できるCPUとかのリソースが多い
...dataを使うことで、dataオブジェクト内のプロパティが展開され、pagePropsと一緒に新しいオブジェクトの一部として返されることになる。
例:
const data = {
user: "Alice",
age: 30
};
return {
pageProps,
...data
};
//上と同じ
return {
pageProps,
user: "Alice",
age: 30
};
BootstrapをNext.jsプロジェクト全体で利用する場合、_app.jsにインポートするだけで大丈夫。これにより、全てのページとコンポーネントでBootstrapのスタイルを利用できるようになる。
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であればその要素を配列に残す)
const items = ['Apple', 'Banana', 'Cherry'];
const itemList = items.map((item, index) => (
<li key={index}>{item}</li>
));
return <ul>{itemList}</ul>;
keyがあるだけで変更がある時に強制再レンダリングはしないけど、setStateなどによってする時は対応するkeyのところだけ再レンダリングする
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コンポーネントと同じクライアントサイドルーティングやスムーズなユーザー体験を提供することはできない。タグではページ全体が再読み込みされ、状態がリセットされるため、ユーザー体験が劣る可能性がある
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>');
});
CMD ["npm", "run", "dev"] 概要: この行は、コンテナが起動されたときに実行されるデフォルトのコマンドを指定 この場合はnpm run dev コマンドを実行