Next.js React TypeScript Docker エラー忘備録
こんばんは
ポートフォリオ作成時に発生したエラー及び、予期せぬ動作に対して、どのようにアプローチしたかを記述しています。
「エラーとその解決方法」というよりかは、動作をしただけです。
ベストプラクティスではないでしょうし、前提としての実装がおかしいということもあります。
私のような未経験の方は斜にかまえてみてもらえると幸いです。
環境
- React 18.2.0
- Next.js(SSR) 13.1.1
- TypeScript 4.6.4
- Jest, React Testing Librar
- prettier, eslint
- TailwindCSS, daisyUI
- docker(node:16.15.0), docker-compose
build時にエラー
Error: Could not find a production build in the '/usr/src/app/.next' directory. Try building your app with 'next build' before starting the production server. https://nextjs.org/docs/messages/production-start-no-build-id
- docker-composeのコマンドで
yarn build
をしてからyarn start
をする必要があった
command: 'yarn build'
Error: Hydration failed because the initial UI does not match what was rendered on the server. Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
- pタグがネストしていた
const isBusinessHourOrNot = (service: ServiceRateType) => {
if (typeof service === "string") {
return service;
} else {
return (
<p>
{service.plan} {service.rate}円
</p>
);
}
};
//pタグの中にpタグが...
<p className="text-sm">
{isBusinessHourOrNot(hotel.stayRates)}
</p>
style
did not match. Server: "display: block; max-width: 100%; width: initial; height: initial; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px …etc
Warning: Prop - Dark Readerというchromeの拡張機能を使ってnext/imageを使ってたら起きるエラー。拡張機能を切ったら消えた
- DarkReaderはブラウザ内にソースを注入するため、事前にレンダリングされるSSG/SSRのツリーとブラウザでの最初のレンダリング時のツリーに相違がおきたため。本番環境では起きない。
react-simple-star-ratingで星のsvgが縦に並んでしまう
- 要素のclass名をchrome devtoolsで調べて、直接CSSを当てて解決
.star-svg {
position: relative;
display: inline-block;
overflow: hidden;
white-space: nowrap;
vertical-align: middle;
user-select: none;
touch-action: none;
}
Error was not TypeError: (0 , _formatUrl).formatWithValidation is not a function
-
docker-composeのvolumeでバインドマウントしていた。
-
node_modulesを含めた全てのファイルをホストマシンとコンテナマシンでバインドマウントしていたので、コンテナUP中にコンテナ内部で更新してホストマシンもそれに同期されていた。
-
本番環境では動作するが、開発環境では何も表示されない。dockerのログは
event - compiled client and server successfully in 2.4s (167 modules)
が通常通り表示されている -
react-simple-star-ratingをdocker-compose up中にrunで入れてからこのエラーが出たので依存関係がおかしいと思い以下を実行した。
yarn cache clean
rm -rf node_modules yarn.lock && yarn install
すると今度は
warn - Attempted to load @next/swc-linux-x64-gnu, but it was not installed
warn - Attempted to load @next/swc-linux-x64-gnux32, but it was not installed
warn - Attempted to load @next/swc-linux-x64-musl, but it was not installed
https://nextjs.org/docs/messages/failed-loading-swc
error - Failed to load SWC binary for linux/x64, see more info here:といったログがでて起動が中断された
- next js のversionを12.2にダウングレードしたら解決したというIssueから、Next jsのversionが関連していると考え、最新versionにアップグレードしたら解決した。
yarn add next@latest react@latest react-dom@latest eslint-config-next@latest
This JSX tag's 'children' prop expects a single child of type 'ReactNode', but multiple children were provided.
- 子をラップするフラグメント
<>
を間に入れることで解決
<div>
{service.plan}
{service.rate}{service.startTime}
</div>
<div>
<>
{service.plan}
{service.rate}{service.startTime}
<>
</div>
Warning: Each child in a list should have a unique "key" prop.
- keyを設定していたつもりだが余計な
<>
が存在した。
// 間違い
{fields.map((field, index) => (
<>
<tbody key={field.id}>
<tr key={field.id}>
<th>{index + 1}</th>
<td>
<>
// 正しい
{fields.map((field, index) => (
<tbody key={field.id}>
<tr key={field.id}>
<th>{index + 1}</th>
<td>
react-responsiveのuseMediaQueryをNext.jsで使ったらError: Hydration failed because the initial UI does not match what was rendered on the server.
- サーバーとクライアントでレンダー結果が異なるのでSSRでは意図した挙動にならない。
- CSSのBreakPointでレスポンシブに対応
no-undef expect' is not defined.eslintno-undef
'describe' is not defined.eslintno-undef 'it' is not defined.eslint-
yarn add -D jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom
をしてNext jsの公式通りjestのライブラリを入れた後に起きたエラー。eslintのプラグインとenvにjestを追加したら解決。
The default export is not a React Component in page
-
export default Home;
のようにpages以下でファイルの最後にexportしたら解決。
useContextを使ってsetStateを更新するときにTypeError is not a function
- そもそもContextAPIで使いたいコンポーネントをラップできていなかった。
TypeError: adapter is not a function
- dockerの再起動で解決
error - AxiosError: connect EADDRNOTAVAIL ::1:80 - Local (:::0)
- Mac再起動時に起きた
- docker-compose buildで解決
This expression is not callable.
Type 'Boolean' has no call signatures.
- useStateの更新関数が逆になっていた
// 間違い
const [setConfirmAlart, confirmAlart] = useState<boolean>(false);
// 正しい
const [confirmAlart, setConfirmAlart] = useState<boolean>(false);
AxiosでPromise { <pending> }が帰ってくる
- awaitのつけ忘れ。
- axios getはデフォルトでpromiseを返すのでawaitか
axios.get(url).then(res => { <resを使った処理> })
で取り出す必要がある。
// 間違い
const response = client.get(`/auth/sessions`);
// 正しい
const response = await client.get(`/auth/sessions`);
getServerSideProps
function did not return an object. Did you forget to add a return
?
Error: Your - try catchのcatchでreturnする必要があった
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const { id } = ctx.query;
try {
const res = await client.get(`/hotels/${id}`);
const hotelDetail: HotelDetailType = await res.data;
return {
props: {
...hotelDetail,
},
};
} catch (error) {
// 間違い
console.log(error);
// 正しい
return {
notFound: true,
};
}
}
The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
- 2つ必要。
// 間違い
uid: ctx.req.cookies["_uid"] | "hoge"
// 正しい
uid: ctx.req.cookies["_uid"] || "hoge"
Refresh performing full reload
- page以下でexportするコンポーネントを大文字にしたら動作
// 間違い
import React from "react";
const rate = () => {
return <div>rate</div>;
};
export default rate;
// 正しい
import React from "react";
const Rate = () => {
return <div>rate</div>;
};
export default Rate;
router.pushでダイナミックルートに遷移するときにリロードされる
- formのonSubmitのデフォルトのイベントとキャンセルする必要があった
{/* 間違い */}
<form
onSubmit={(e) => {router.push(`search?keyword=${searchWord}`);
}}>
{/* 正しい */}
<form
onSubmit={(e) => {
e.preventDefault();
router.push(`search?keyword=${searchWord}`);
}}>
next export
Error: Image Optimization using Next.js' default loader is not compatible with - next.jsはビルド時ではなく、ユーザーからのリクエストを受けたオンデマンド時に画像を最適化するため、デフォルトのローダーのままnext exportは出来ない。
- 一つの解決策としては下記のようにして、ソース画像の画質、サイズ、フォーマットを変更することなくそのまま提供するように変更する。
module.exports = {
experimental: {
images: {
unoptimized: true
}
}
}
CustomerError: Cannot read 'next' version in package.json
- AmplifyでSSRを使う場合、package.jsonをnext buildのみにする
// エラー
"build": "next build && next export"
// 動作
"build": "next build"
Your app will appear here once you complete your first deployment.
- バックエンドのapiを起動していなかった。
A client-side exception has occurred, see here for more
- props.mapで展開していたが、propsが配列ではなかった。
- develop環境で同じアクションをしたら、エラーが起きたので、それが原因だった。
Amplifyでデプロイしたサイトとlocalhostでproduction環境でのCSS,UIが違う
- ブレイクポイントの設定で、mdは設定していたが、lgの設定をしていなかったため、サイトで開いたときに差異が生じた。
- 特に、アスペクト比の異なる画像をfillで設定している場合、画像サイズも指定する必要があるが、relativeでwidhtとheightを指定している場合はlgの指定もしっかりしないと、UIが崩れる。
ESLint
ESLint couldn't find the plugin "eslint-plugin-jest".
- eslint-plugin-jestを
yarn add
して解決
Oops! Something went wrong! :(
ESLint: 8.31.0
ESLint couldn't find the plugin "eslint-plugin-jest".
(The package "eslint-plugin-jest" was not found when loaded as a Node module from the directory "/usr/src/app".)
It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:
npm install eslint-plugin-jest@latest --save-dev
The plugin "eslint-plugin-jest" was referenced from the config file in ".eslintrc.js".
If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.
error Command failed with exit code 2.
Array.prototype.map() expects a return value from arrow function
- mapを使っているのにmapから生成される配列を使っていなかった。
- 単純な繰り返し処理だけしたい場合はforEach。
services.map((service: HotelRateParams) => {
postServiceListByWeekdays(service);
}),
services.forEach((service: HotelRateParams) => {
postServiceListByWeekdays(service);
}),
Component definition is missing display name react/display-name
- メモ化しているコンポーネントで発生。アロー関数を名前付きの関数に変更して解決。
React version not specified in eslint-plugin-react setting
- eslintにreact detectを追加することで、自動的にReactのバージョンをピックアップできる
settings: {
react: {
version: "detect",
}
Jest
NextRouter was not mounted
- テストファイルにuseRouterをモックする必要がある
jest.mock("next/router", () => ({ useRouter: jest.fn() }));
TypeError: Cannot read properties of undefined (reading 'mockResolvedValueOnce')
- モック化に失敗している
- 型アサーションを使ってjest.Mock型にキャストすることで解決
(getHoge as jest.Mock).mockResolvedValueOnce(mockResponse);
expect(received).toBeInTheDocument() received value must be an HTMLElement or an SVGElement. Received has type: object Received has value: {}
- findはプロミスを返すので非同期で待つ必要がある
expect(screen.findByAltText("アバター")).toBeInTheDocument();
expect(await screen.findByAltText("アバター")).toBeInTheDocument();
Discussion