Reputation: 261
Normally if I get an error when using .map it's because the array on which I'm using the method either doesn't exist or isn't an array at all.
Sometimes I return a JSON object from a fetch and I try to use .map on the object instead of an array that's inside of the object.
These are rookie errors, and I am a rookie. However, in the following case I'm sure that I am calling the .map on an array that is inside of a JSON object.
How?
When I deploy this next.js app on Vercel, I get the following error:
> Build error occurred
21:23:30 TypeError: albums.map is not a function
21:23:30 at getStaticPaths (/vercel/workpath0/.next/serverless/pages/albums/[id].js:306:16)
21:23:30 at processTicksAndRejections (internal/process/task_queues.js:97:5)
21:23:30 at async buildStaticPaths (/vercel/workpath0/node_modules/next/dist/build/utils.js:16:80)
21:23:30 at async Object.isPageStatic (/vercel/workpath0/node_modules/next/dist/build/utils.js:23:549) {
21:23:30 type: 'TypeError'
21:23:30 }
21:23:30 error Command failed with exit code 1.
21:23:30 info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
21:23:30 Error: Command "yarn run build" exited with 1
21:23:32 Done with "package.json"
Here's the page this error is referring to:
import React from "react";
import { useQuery, useMutation, useQueryClient } from "react-query";
import Image from "next/image";
import { queryAlbum } from "../../api/albums/[id]";
import { queryAlbums } from "../../api/albums";
import Form from "../../../components/styles/Form";
import Button from "../../../components/styles/Button";
import Container from "../../../components/styles/AlbumsShow";
async function createPicture(pictureData) {
const response = await fetch(`/api/pictures/create`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(pictureData),
});
const { picture } = response.json();
return picture;
}
async function deletePicture(pictureId) {
await fetch(`/api/pictures/delete`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(pictureId),
});
}
export async function getStaticPaths() {
const albums = queryAlbums();
const paths = [];
await albums.map((album) => {
return paths.push({
params: {
id: album.id.toString(),
},
});
});
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const response = await queryAlbum(params.id);
const data = await JSON.stringify(response);
const initialAlbumData = await JSON.parse(data);
return {
props: {
initialAlbumData,
},
};
}
export default function Album({ initialAlbumData }) {
...all the code for the component
);
}
and here are the query functions:
import { PrismaClient } from "@prisma/client";
export async function queryAlbum(albumId) {
const prisma = new PrismaClient({ log: ["query"] });
try {
const album = await prisma.album.findUnique({
where: {
id: parseInt(albumId),
},
include: {
pictures: true,
},
});
return album;
} catch (error) {
return { error: error };
} finally {
prisma.$disconnect();
}
}
export default async function answerQuery(req, res) {
// get [id] from url
const {
query: { id },
} = req;
const album = await queryAlbum(id);
res.json({ album: album });
}
and:
import { PrismaClient } from "@prisma/client";
export async function queryAlbums() {
const prisma = new PrismaClient({ log: ["query"] });
try {
const albums = await prisma.album.findMany();
return albums;
} catch (error) {
return { error: error };
} finally {
prisma.$disconnect();
}
}
export default async function Albums(req, res) {
const albums = await queryAlbums();
res.json({ albums: albums });
}
For a little context on why I chose to import queryAlbum and queryAlbums, here's a thread on Git that I used to base my code on: https://github.com/vercel/next.js/discussions/13648
Upvotes: 2
Views: 2949
Reputation: 261
I solved this problem in two steps.
First, I found an answer on Git: https://github.com/vercel/next.js/issues/8041. Basically, all I needed to do was delete the "babel" configurations. I really don't know why this answer works. I'll look into it and post updates here.
package.json that causes the error on deploy:
{
"name": "photo_album",
"version": "0.1.0",
"private": true,
"scripts": {
"prisma": "prisma",
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@prisma/client": "^2.13.1",
"babel-plugin-styled-components": "^1.12.0",
"next": "10.0.3",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-query": "^3.5.1",
"styled-components": "^5.2.1"
},
"devDependencies": {
"@prisma/cli": "^2.13.1"
},
"babel": {
"presets": [
"@babel/preset-react"
],
"env": {
"development": {
"presets": [
"next/babel",
"@babel/preset-react"
"next/babel"
],
"plugins": [
[
the answer:
{
"name": "photo_album",
"version": "0.1.0",
"private": true,
"scripts": {
"prisma": "prisma",
"dev": "next dev",
"build": "next build",
"start": "next start -p $PORT",
"postinstall": "prisma generate",
"heroku-postbuild": "npm run build"
},
"dependencies": {
"@prisma/client": "^2.13.1",
"babel-plugin-styled-components": "^1.12.0",
"next": "10.0.3",
"react": "16.13.0",
"react-dom": "17.0.1",
"react-query": "^3.5.1",
"styled-components": "^5.2.1",
"@prisma/cli": "^2.13.1",
"@babel/core": "^7.12.10",
"@babel/preset-react": "^7.12.10"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-react": "^7.12.10",
"@prisma/cli": "^2.13.1"
}
}
The second step involved changing getStaticProps to getServerSideProps and DELETING getStaticPaths. Here's what getServerSideProps looks like:
export async function getServerSideProps(context) {
const response = await queryAlbum(context.query.id);
const data = await JSON.stringify(response);
const initialAlbumData = await JSON.parse(data);
if (!initialAlbumData) {
return {
notFound: true,
};
}
return {
props: {
initialAlbumData,
},
};
}
Upvotes: 1
Reputation: 3317
Looking at the import, seems these are api you created. These are not normal methods, they are http methods, can be consume over http(http call).
import { queryAlbum } from "../../api/albums/[id]";
import { queryAlbums } from "../../api/albums";
I am using fetch
to consume respective apis.
export async function getStaticPaths() {
const data = await fetch('/api/albums');
const albums = await data.json();
const paths = await albums.map((album) => {
return paths.push({
params: {
id: album.id.toString(),
},
});
});
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const response = await fetch(`/api/albums/${params.id}`);
const data = await response.json();
return {
props: {
initialAlbumData: data,
},
};
}
Upvotes: 0