So there is a indexpage with components, listing ads.
const App = ({ads}) => (
{ (ads.items===undefined) ? <></> : ads.items.map(item => <Ad item={item} key={item.postingId} id={item.postingId}/>) }
)
export async function getServerSideProps(context) {
const res = await fetch(`www.apiadress.com/${queryString.stringify(context.query)}`)
const ads = await res.json()
// console.debug(ads)
console.debug(queryString.stringify(context.query))
return {
props: {ads}, // will be passed to the page component as props
}
}
and component Ad receives those props, and renders cards
const Ad = props => (
<Card className="customCard">
<Card.Body>
<Card.Text className="text">
<div className="mainDetails">
<h1 className="ad_Title"><Link href="[ad]" as={props.item.postingId}>{props.item.title}</Link></h1>
<p>posted on: {props.item.postingDate.day} / {props.item.postingDate.month}
{props.item.postingDate.year} by {props.item.employer}
</p>
<div className="description">
<p><span><Cash /><b> {props.item.rateFrom}- {props.item.rateTo} per hour </b></span> <GeoAlt /> <b>{props.item.city}</b></p>
<p> <Clock /> <b>{props.item.jobType}</b></p>
</div>
<p>{props.item.description.slice(0, 230)}.....</p>
</div>
<div>
<img src={props.item.employerLogoUrl} alt={props.item.employer} className="empImg" />
<Button variant="primary" href=""> <Heart width="12" height="12"/> SHORLIST </Button>
</div>
</Card.Text>
</Card.Body>
</Card>
export default Ad;
with NPM run dev - everything works perfectly but at NPM run build I am getting an error
Error occurred prerendering page "/componenets/ad/ad". Read more:
https://err.sh/next.js/prerender-error TypeError: Cannot read property
'postingId' of undefined
What's causing this? I am assuming that components does not have data before render.
How to solve this problem?
it simply that you have some items in your array null so it caused that error. I suggest to rewrite like this so it can avoid unnecessary error
const App = ({ads}) =>
(ads.items || []).map(item => item ? <Ad item={item} key={item.postingId} id={item.postingId}/> : null)
props.item is empty on cards component.
Add validation check in the start of the Ad component:
if (!props.item) {
return null;
}
Related
I googled this message but didn't find solution to it. The error occurs when I try to access my dynamic route:
from react component:
function MeetupItem(props) {
const router = useRouter()
const showDetailsHandler = () => {
router.push('/' + props.id);
}
return (
<li className={classes.item}>
<Card>
<div className={classes.image}>
<img src={props.image} alt={props.title} />
</div>
<div className={classes.content}>
<h3>{props.title}</h3>
<address>{props.address}</address>
</div>
<div className={classes.actions}>
<button onClick={showDetailsHandler}>Show Details</button>
</div>
</Card>
</li>
);
}
export default MeetupItem;
meetUpId I receive from mongoDB but IMO it's nothing wrong here. Stack trace of an error is:
Where to start? What's useDebugValue? Something wrong with styledComponents?
Thank you in advance!
I had the same errors on a different case and they were solved by installing the latest node js version. I would try doing that if you haven't already. Hope that helps!
I created a project using NextJS template Blog starter kit, found here: https://vercel.com/templates/next.js/blog-starter-kit
I've successfully fetched my own posts from a graphql-endpoint and can render them, but when I add values to the post object on my own that weren't included in the original NextJS-project and pass them down to child components, they are available at first but then go undefined and throw an error if I try to use those values.
Please see below code and screenshot of how the values goes from defined to undefined.
I'm new to both Typescript and NextJS but have used React for some time, but I can't grasp why this happens. The code below renders, but I'd like to understand why just some of the props goes undefined, after clearly being included. Also in this specific example I'd like to be able to use coverImage.width in the Image component width-property instead of hardcoding a value.
index.tsx
type Props = {
allPosts: Post[]
}
export default function Index({ allPosts }: Props) {
const heroPost = allPosts[0]
const morePosts = allPosts.slice(1)
return (
<>
<Layout>
<Head>
<title>SWG - Blog</title>
</Head>
<Container>
<Intro />
{heroPost && (
<HeroPost heroPost={heroPost} />
)}
{morePosts.length > 0 && <MoreStories posts={morePosts} />}
</Container>
</Layout>
</>
)
}
export const getStaticProps = async () => {
const allPosts = (await getPosts()) || [];
return {
props: { allPosts },
}
}
hero-post.tsx. All heroPost-prop values are available here. Please see below image of console print as well (image link until I have 10 points on SO).
type Props = {
heroPost: {
title: string
coverImage: {
url: string
width: number
height: number
}
date: string
excerpt: string
author: Author
slug: string
}
}
const HeroPost = ({ heroPost }: Props) => {
return (
<section>
<div className="mb-8 md:mb-16">
<CoverImage title={heroPost.title} src={heroPost.coverImage.url} slug={heroPost.slug} coverImage={heroPost.coverImage} />
</div>
<div className="md:grid md:grid-cols-2 md:gap-x-16 lg:gap-x-8 mb-20 md:mb-28">
<div>
<h3 className="mb-4 text-4xl lg:text-5xl leading-tight">
<Link as={`/posts/${heroPost.slug}`} href="/posts/[slug]">
<a className="hover:underline">{heroPost.title}</a>
</Link>
</h3>
<div className="mb-4 md:mb-0 text-lg">
<DateFormatter dateString={heroPost.date} />
</div>
</div>
<div>
<p className="text-lg leading-relaxed mb-4">{heroPost.excerpt}</p>
<Avatar name={heroPost.author.name} picture={heroPost.author.picture} />
</div>
</div>
</section>
)
}
export default HeroPost
cover-image.tsx. Here's where the props of heroPost goes missing, but only the ones I've declared. Not "src" for example.
type Props = {
title: string
src: string
slug?: string
coverImage: {
url: string
width: number
height: number
}
}
const CoverImage = ({ title, src, slug, coverImage }: Props) => {
console.log(src);
//console.log(title);
console.log(coverImage);
const image = (
<>
<Image src={src} width={1495} height={841} />
</>
)
return (
<div className="sm:mx-0">
{slug ? (
<Link as={`/posts/${slug}`} href="/posts/[slug]">
<a aria-label={title}>{image}</a>
</Link>
) : (
image
)}
</div>
)
}
export default CoverImage
Apparently I can't post images since I'm a new member, but the above console.logs prints like this:
coverImage object exists
prop.src = correct src.value
props.coverImage = cover-image.tsx?0fdc:19 full coverImage object printed
Don't know where these react-devtools-backend lines come from but same thing here, both values exist.
react_devtools_backend.js:4082 correct src.value
react_devtools_backend.js:4082 full coverImage object printed
coverImage then goes undefined
cover-image.tsx?0fdc:19 undefined
but src in props still return its value
cover-image.tsx?0fdc:17 correct src.value
cover-image.tsx?0fdc:19 undefined
same thing with the lines from react_devtools_backend:
react_devtools_backend.js:4082 correct src.value
react_devtools_backend.js:4082 undefined
I've read numerous SO-threads and looked through the NextJS-docs but fail to realise what I'm doing wrong.
console.log of heroPost-object in hero-post component.
I am working on e-commerce project (MERN).So i got Molla e-commerce React template for better UX/UI.
In my root function am getting all products and store them using redux like this :
const updateStore = () => {
store.dispatch( getAllProducts() );
}
Everything was working fine until i found out that if i try to access product page for the first time (with empty localstorage as in incognito mode) i get nothing and the product object was undefined , if i refresh the page then it works fine.
The problem is when i try to access the products page with empty redux store , it doesn't wait or rerender when the data are stored.
I tryed to use useEffect() to wait for product change to rerender but it's not working .
This is my product page code :
function SingleProduct( props ) {
let productLink= props.match.params.link;
const {product} = props;
const [productLoaded,setProductLoaded] = useState(false);
useEffect( () => {
if(productLoaded){
productGallery();
document.querySelector( '.skel-pro-single' ).classList.remove( 'loaded' );
let imgLoad = imagesLoaded( ".product-main-image", { background: true } );
imgLoad.on( 'done', function ( instance, image ) {
document.querySelector( '.skel-pro-single' ).classList.add( 'loaded' );
} );
}
}, [ productLink ] )
useEffect(()=>{
if(product){
setProductLoaded(true);
}
},[product])
return (
productLoaded ?
<>
<Helmet>
<title></title>
</Helmet>
<h1 className="d-none"></h1>
<div className="main">
<div className="page-content">
<div className="container">
<div className="product-details-top skeleton-body">
<div className="row skel-pro-single">
<div className="col-md-6">
<div className="skel-product-gallery">
</div>
<MediaOne link={ productLink } />
</div>
<div className="col-md-6">
<div className="entry-summary row">
<div className="col-md-12">
<div className="entry-summary1"></div>
</div>
<div className="col-md-12">
<div className="entry-summary2"></div>
</div>
</div>
<ProductDetailOne link={ productLink } />
</div>
</div>
</div>
<DescOne link={ productLink } />
<h2 className="title text-center mb-4">You May Also Like</h2>
<RelatedProducts />
</div>
</div>
<StickyBar link={ productLink } />
<QuickView />
</div>
</>
:
<></>
)
}
function mapStateToProps( state, props ) {
return {
product: state.data.products.filter( product => product.link == props.link )[ 0 ]
}
}
export default connect(mapStateToProps)(SingleProduct);
I tried to wait for product change using the useEffect and productLoaded state since it's undefined on first page render but it still showing undefined.
'product' variable, I think, is an object, be aware about what could happen if you use useEffect with that.
const a = {a:123};
const b = {a:123};
(a === b) === false
if it is possible see if the id or a string/number changes
The first useEffect will run before the second one so when this will run it will have productLoaded on false.
Try to gain productLoaded from props (you will not have to manage the asyncronicity of useEffect).
assuming that product is undefined before loading
const productLoaded = !!product;
useEffect( () => {
if(productLoaded){
..."do here what you need"
}
}, [ productLink, productLoaded ] )
maybe you can achieve a change in the css classes
<div className={`row skel-pro-single ${productLoaded?"loaded":""}`}>
as a suggestion try to use react as a templating with variables in the returning jsx, please don't mix js dom interaction and react interactions, they could disturb each other (react will try to report the part of the dom that he manages to the state he calculated, so could overwrite your changes made by
document.querySelector( '.skel-pro-single' ).classList.remove
I'm getting an error that map is not a function on my data.
I'm getting a response back from an api that is returning an array of objects. When I don't refresh the page I can view the results displayed just fine and even navigate to view them individually (when I click on see more). However, when I refresh the page I get the
error of "Map is not a function" on my props even though the results are displaying in the console log.
I'm lost here and can't figure out why it's doing that.
componentDidMount() {
this.props.getCanyons();
}
render() {
const { canyons } = this.props;
console.log(canyons)
return (
<section>
{canyons.map(canyon => (
<section key={canyon.canyon_id}>
<h3>{canyon.canyon_name}</h3>
<img src={canyon.canyon_pic} alt={canyon.canyon_name} />
<Link key={canyon.canyon_id} to={`/canyon/${canyon.canyon_id}`}>
<button>See More</button>
</Link>
</section>
))}
</section>
);
}
}
When the api failed or having lag time to get response, it may be undefined. This kind of checking prevent you to from such problem.
return (
{canyons && canyons.map(canyon => (
...skipped code
))}
)
Typescript provide feature of adding a ? before try to access the related Object type variable
//In typescript
{canyons?.map(canyon => (
...skipped code
))}
componentDidMount() {
this.props.getCanyons();
}
render() {
const { canyons } = this.props;
console.log(canyons)
return (
<section>
{ canyons !== '' || canyons.length > 0 ? //change here
canyons.map(canyon => (
<section key={canyon.canyon_id}>
<h3>{canyon.canyon_name}</h3>
<img src={canyon.canyon_pic} alt={canyon.canyon_name} />
<Link key={canyon.canyon_id} to={`/canyon/${canyon.canyon_id}`}>
<button>See More</button>
</Link>
</section>
))
:
null
}
</section>
);
}
}
Please follow the change. It should works for you...
Many browsers provide a live view when using console.log(). When the request not finished 'canyons' is undefined. Use
console.log(JSON.parse(JSON.stringify(obj)))
For this problem, try to set default value or check variable first
I'm making a Nextjs flashcard app. I'm passing a deck structure like this:
const deck = {
title: 'React 101',
flashcards: [flashcardOne, flashcardTwo],
};
as props to the Deck component. This component shows the first card in flashcards and a "next" button to increment the index and showing the next card in flashcards.
The Card component is very simple and shows the front and the back of the card depending of the state front.
This is what I got so far and it's working but if I click "next" when the card is showing the answer (flashcard.back), the next card is going to appear with the answer. And I'm not sure why, isn't the Card component re rendering when I click "next"? And if the component re renders, front is going to be set to true?
export default function Deck({ deck }) {
const [cardIndex, setCardIndex] = useState(0);
const { title, flashcards } = deck;
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>{title}</h1>
{cardIndex < flashcards.length ? (
<>
<div className={styles.grid}>
<Card flashcard={flashcards[cardIndex]} />
</div>
<button onClick={() => setCardIndex((cardIndex) => cardIndex + 1)}>
Next
</button>
</>
) : (
<>
<div>End</div>
<button>
<Link href='/'>
<a>Go to Home</a>
</Link>
</button>
<button onClick={() => setCardIndex(0)}>Play again</button>
</>
)}
</main>
</div>
);
}
export function Card({ flashcard }) {
const [front, setFront] = useState(true);
return (
<>
{front ? (
<div
className={`${globalStyles.card} ${styles.card}`}
onClick={() => setFront(false)}
>
<p className={styles.front}>{flashcard.front}</p>
</div>
) : (
<div
className={`${globalStyles.card} ${styles.card}`}
onClick={() => setFront(true)}
>
<p className={styles.back}>{flashcard.back}</p>
</div>
)}
</>
);
}
When state changes, the card will re-render, but it will not re-mount. So, existing state will not be reset.
Call setFront(true) when the flashcard prop has changed:
const [front, setFront] = useState(true);
useLayoutEffect(() => {
setFront(true);
}, [flashcard]);
I'm using useLayoutEffect instead of useEffect to ensure front gets set ASAP, rather than after a paint cycle (which could cause flickering).
You can also significantly slim down the Card JSX:
export function Card({ flashcard }) {
const [front, setFront] = useState(true);
const face = front ? 'front' : 'back';
return (
<div
className={`${globalStyles.card} ${styles.card}`}
onClick={() => setFront(!front)}
>
<p className={styles[face]}>{flashcard[face]}</p>
</div>
);
}
Okay, I guess I had the same issue. Since you're using functional components, and you're re-using the same component or in better words, you're not unmounting and remounting the component really, you're just changing the props, this happens. For this, you need to do useEffect() and then setFront(true).
Here's the code I used in my App.
useEffect(() => {
setFront(true);
}, [flashcard]);
This is what I have used in my Word.js file.