Nextjs getInitialProps query.id is undefined - reactjs

I am trying to get the id from the route as http//localhost:3000/portfolios/helloworld so id is helloworld. But i get an error that says TypeError: Cannot destructure property 'id' of 'query' as it is undefined.
const PortfolioDetail = ({ query }) => {
const { id } = query;
return <h1>I am Details Page with ID: {id}</h1>;
};
PortfolioDetail.getInitialProps = ({ query }) => {
return { query };
};
export default PortfolioDetail;
I tried the same thing with class component but the error was same.
// class PortfolioDetail extends React.Component {
// static getInitialProps({ query }) {
// return { query };
// }
// render() {
// const id = this.props.query.id;
// return <h1>I am Detail Page with id : {id} </h1>;
// }
// }
// export default PortfolioDetail;
this is my project structure you can see below image
It only works and i can get my id using useRouter i showed below.
import { useRouter } from 'next/router';
import React from 'react';
const PortfolioDetail = () => {
const router = useRouter();
const id = router.query.id
return <h1>I am Details Page with ID: {id}</h1>;
};
PortfolioDetail.getInitialProps = ({ query }) => {
return { query };
};
export default PortfolioDetail;
I am stuck at this point and i really wanna know why it won't work.

I've got it, you have an error in your _app:
import '../styles/index.scss';
import 'bootstrap/dist/css/bootstrap.min.css';
// Don't need to spread pageProps here
const MyApp = ({ Component, ...pageProps }) => {
return <Component {...pageProps} />;
};
export default MyApp;
It should be:
const MyApp = ({ Component, pageProps }) => {
return <Component {...pageProps} />;
};

Why dont use it like the code shown below
export default function FirstPost({ id }) {
console.log("-->", id);
return (
<>
{id}sdlfdfdlkj
</>
);
}
FirstPost.getInitialProps = ({ query }) => {
return { id: query?.id };
};

Related

Nextjs not server side rendered when i wrapped component by auth

I using Next.js for SSR, after I try to make authentication for user client by Auth component following to my idea. But I have a problem when View Source page, it not loaded as HTML tag which empty root like create-react-app, now it my code in _app.js:
function MyApp({ Component, pageProps: { ...pageProps } }) {
const { auth } = Component;
return (
<>
{
auth ?
<Auth>
<Component {...pageProps} />
</Auth>
:
<Component {...pageProps} />
}
</>
)
}
Which Auth component is:
export const Auth = async (props) => {
const { children } = props;
const auth = await POST('http://localhost:7000/services/api/auth');
if (!auth) {
return <div>Loading...</div>
}
return children
}
And the page wrapped by auth component is:
export const getServerSideProps = async ctx =>{
const { id } = ctx.query;
try {
const postById = await GET(`http://localhost:7000/services/api/post/${id}`);
return {
props: {
post: postById
},
}
}
catch (err) {
console.log(err)
}
}
export default const DetailPost = (props) => {
return (
...
)
}
What should I do it for rendered with HTML DOM like server-side-rendering?

How to fetch category page data inside component in Next.js?

I would like to create a category page containing all tags added to articles. When clicking on a tag it should show a page with all articles containing that specific tag.
I'm using Next.js, SSG, and fetching the articles from Contentful with the following GraphQL query:
export async function getArticles() {
const articlesQuery = gql`
{
articleCollection {
items {
title
slug
excerpt
date
contentfulMetadata {
tags {
name
id
}
}
featuredImage {
title
url
width
height
}
}
}
}
`;
return graphQLClient.request(articlesQuery);
}
The contentfulMetadata is where the tags come from:
contentfulMetadata {
tags {
name
id
}
}
I've then created a CategorySection component:
import styled from "styled-components";
import { getArticles } from "../../utils/contentful";
import Link from "next/link";
export async function getStaticProps() {
const categories = await getArticles();
return {
props: {
categories: categories.articleCollection.items,
},
};
}
export default function CategorySection({ categories }) {
return (
<Wrapper>
<ContentWrapper>
<CategoryWrapper>
{categories.map((category) => {
return (
<Link href={`/articles/categories/${category.tags.name}`}>
<Categories key={category.tags.id}>
{category.tags.name}
</Categories>
</Link>
);
})}
</CategoryWrapper>
</ContentWrapper>
</Wrapper>
);
}
The CategorySection component gives me the following error message:
TypeError: Cannot read property 'map' of undefined"
Below is my /pages/articles/categories/[slug].jsx file:
import styled from "styled-components";
import { getArticles, getArticle } from "../../utils/contentful";
export async function getStaticPaths() {
const data = await getArticles();
return {
paths: data.articleCollection.items.map((article) => ({
params: { slug: article.contentfulMetadata.tags.id },
})),
fallback: false,
};
}
export async function getStaticProps(context) {
const data = await getArticle(context.params.slug);
return {
props: { article: data.articleCollection.items[0] },
};
}
export default function Category({ article }) {
return <h1>{article.contentfulMetadata.tags.name}</h1>;
}
I'm getting the error below:
Error: A required parameter (slug) was not provided as a string in
getStaticPaths for /articles/categories/[slug]
Can you help me understand how I create dynamic pages from my categories (tags)?
getStaticProps can only be used in page components, so in your case it'll be completely ignored in your CategorySection component. You'll need to fetch the data at the page level and pass it to the component where you want to use it.
One possible solution is to simply pass the data as a prop down to the desired component.
// pages/article
import { getArticles } from "../../utils/contentful";
export async function getStaticProps() {
const categories = await getArticles();
return {
props: {
categories: categories.articleCollection.items
}
};
}
export default function ArticlePage({ categories }) {
return (
<CategorySection categories={categories} />
);
}

How to get previous page url in nextjs

i created a _app.js file and added this code to it witch should store state of previous url in an array. When trying to access the previous url i just get the current page url.
Is there something wrong in the logic of the _app.js code or in passing the history value to other components/pages?
_app.js
import React from 'react';
import App from 'next/app';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
}
state = {
history: []
};
componentDidMount() {
const { asPath } = this.props.router;
this.setState(prevState => ({ history: [...prevState.history, asPath] }));
}
componentDidUpdate() {
const { history } = this.state;
const { asPath } = this.props.router;
if (history[history.length - 1] !== asPath) {
this.setState(prevState => ({ history: [...prevState.history, asPath] }));
}
}
render() {
const { Component, pageProps } = this.props
return <Component history={this.state.history} {...pageProps} />
}
}
export default MyApp;
Example of passing history
const CatPage = ({ history }) => {
console.log(history) //I get the value of a current page
console.log(history[0]) // same thing it is just the current url in the array
}

React-Redux. I can view my array in state but cant map over it

I can see that projects exist when I log it but trying to call map gives me an undefined error
import React, { Component } from "react";
import { connect } from "react-redux";
import Project from "./Project";
const ProjectsContainer = ({ projects }) => {
const allProjects = projects.map((project, index) => (
<Project key={index} project={project} />
));
return <div></div>;
};
const mapStateToProps = (state) => {
console.log(state);
return {
projects: state.projects,
loggedIn: !!state.currentUser
};
};
export default connect(mapStateToProps)(ProjectsContainer);
UPDATE
this happens after I log in. I get TypeError: projects.map is not a function
But if I refresh the page it works
import React, { Component } from "react";
import { connect } from "react-redux";
import Project from "./Project";
const ProjectsContainer = ({ projects =[] }) => {
const allProjects = projects.map((project, index) => (
<Project key={index} project={project} />
));
return <div></div>;
};
const mapStateToProps = (state) => {
console.log(state);
return {
projects: state.projects,
loggedIn: !!state.currentUser
};
};
export default connect(mapStateToProps)(ProjectsContainer);

Pass value from a component to context, and use the value in componentDidMount() method

I get the pathname in the WorldPage component and pass this value to the context.jsx in which I want to request data using the pathname.
However, I cannot get the correct value in the componentDidMount() method.
console.log(this.state.tab) should be /world, but still /home.
import axios from "axios";
export const Context = React.createContext();
export class Provider extends Component {
state = {
news_list: [],
tab: "/home",
tabChange: (tabName) => {
if (this.state.tab !== tabName) {
this.setState({
tab: tabName,
});
}
},
};
componentDidMount() {
console.log(this.state.tab);
axios
.get(this.state.tab)
.then((res) => {
console.log(res.data);
this.setState({
news_list: res.data,
});
// console.log(this.state.news_list);
})
.catch((err) => console.log(err));
}
render() {
return (
<Context.Provider value={this.state}>
{this.props.children}
</Context.Provider>
);
}
}
export const Consumer = Context.Consumer;
import React, { Component } from "react";
import News from "../News/News";
import { Consumer } from "../../context";
export default class WorldPage extends Component {
render() {
const tabName = window.location.pathname;
return (
<Consumer>
{(value) => {
const { tabChange } = value;
tabChange(tabName);
console.log(tabName);
return (
<React.Fragment>
<News />
</React.Fragment>
);
}}
</Consumer>
);
}
}

Resources