fetching data from component in NextJS - javascript

Hi i am sorry if this question is too basic. But I recently started learning React and NextJS. I am creating simple application that fetch some data and display it on Home page. I have two functions in my component file. I imported that component file in my index.js and using it as composition. The error says map is returning data of undefined.
// Names.js Component
export const getStaticProps = async () => {
const prisma = new PrismaClient()
const names = await prisma.name.findMany()
return {
props: {
names
}
}
}
function Data({names}) {
return (
<div>
<ul>
{names.map((namelist) => (
<li key={namelist.id}>{namelist.title}</li>
))}
</ul>
</div>
)
}
export default Data
// Index.js
export default function Home() {
return(
<div>
<Names />
</div>
)
}

getStaticProps can only be called from pages, not from components. You'll need to move it to Index.js (assuming that's under /pages folder).
// Index.js
export default function Home({ names }) {
return(
<div>
<Names names={names} />
</div>
)
}
export const getStaticProps = async () => {
const prisma = new PrismaClient()
const names = await prisma.name.findMany()
return {
props: {
names
}
}
}
// Names.js Component
function Data({ names }) {
return (
<div>
<ul>
{names.map((namelist) => (
<li key={namelist.id}>{namelist.title}</li>
))}
</ul>
</div>
)
}
export default Data

Related

How to dynamically import react component inside file based on prop

I have a file (in this case Test.js) that will have many small components in the future (at the moment just Test and SuperTest).
I don't want to import the whole file in order to optimize performance. I try to import just the component I need. Not the whole file.
In the example, prop can be either "Test" or "SuperTest".
It throws an error Unexpected token (7:26)
Is there any way to accomplish that? and then render that into App?
App.js
import { useState } from 'react';
// import Test from './Test';
function App({prop}) {
const [Comp, setComp] = useState(null);
import('./Test').then(({`${prop}`: newComp}) => { // This is an ERROR
console.log(typeof newComp); // Object
setIcon(() => newComp);
});
return (
<div className="App">
<Comp />
</div>
);
}
export default App;
Test.js
export const Test = () => {
return (
<div>
Hello People
</div>
);
}
export const SuperTest = () => {
return (
<div>
Hello People 2
</div>
);
}
If you want to use many functions/components in single file and have to call the function dynamically then try below code.
Add getData() function to invoke the function in Test.js file.
Test.js
const Test = () => {
return (
<div>
Hello People
</div>
);
}
const SuperTest = () => {
return (
<div>
Hello People 2
</div>
);
}
export function getData(fnName) {
switch (fnName) {
case "Test":
return Test();
default:
return SuperTest();
}
}
Call getData() function and pass your prop as parameter
App.js
import("./Test").then((fn) => {
let newComp = fn.getData({prop}));
// use above newComp value
});
don't wrap props in this {props}. try this one:
function App(prop) {
const [Comp, setComp] = useState(null);

Importing data from api to new module - .map() not a function

Below is the code for my biggest nightmare yet. I keep on getting the error that the apiData.map is not a function. Any body that can help please.
I also need to know why ApiGetData do not use react please.
I do get the api data but seems that I'm importing it incorrectly to ClassFilmData and I get the .map error. All help will be appreciated.
Tried to export films, ApiGetData in various way. Help received from other platforms was implemented but did not solve the problem. Searches - other swapi projects, import data react, sandbox, repo and other platforms
// import React from 'react';
import { ApiToGet } from "./ApiToGet";
const ApiGetData = async function() {
try {
const films = await Promise.all(
ApiToGet.map(url => fetch(url).then(resp => resp.json()))
);
console.log("film title - ", films.results);
return films;
} catch (err) {
console.log("oooooooops", err);
}
};
ApiGetData();
export default ApiGetData;
import React from "react";
import FilmsInfo from "./FilmsInfo";
const FilmsLoop = ({ apiData }) => {
return (
<div className="tc f1 unknown">
{apiData.map((answers, i) => {
return (
<FilmsInfo
key={i}
// title={ apiData.films.results[i].title }
/>
);
})}
</div>
);
};
export default FilmsLoop;
import React, { Component } from "react";
import FilmsLoop from "./FilmsLoop";
import ApiGetData from "./ApiGetData";
class ClassFilmData extends Component {
render() {
return (
<div>
<p className="tc f1">Wim - classfilmdata</p>
<FilmsLoop apiData={ApiGetData} />
</div>
);
}
}
export default ClassFilmData;
import React from "react";
const FilmsInfo = () => {
return (
<div className="tc bg-light-blue dib br3 pa3 ma3 grow bw2 shadow-5">
<p>Planet</p>
<p>FilmsInfo.js</p>
</div>
);
};
export default FilmsInfo;
That is because apiData is really ApiGetData which is a promise.
If you're trying to use the array returned by resolving this promise, you'll have to do something like this:
class ClassFilmData extends Component {
componentDidMount() {
const apiData = await ApiGetData();
this.setState({ apiData });
}
render() {
return(
<div>
<p className="tc f1">Wim - classfilmdata</p>
{this.state.apiData && <FilmsLoop apiData={ this.state.apiData }/> }
</div>
);
}
}

Unhandled Rejection (TypeError): Cannot read property 'map' of undefined when doing React tutorial

Doing a Hacker News Clone tutorial in React and Next.js, but I'm stumbling into a problem. I have read other questions that are dealing with the same error, but the solutions offered don't work for me. Here is the code:
import React from 'react';
const StoryList = ({ stories }) => (
<div>
{stories.map(story => (
<h3 key={story.id}>{story.title}</h3>
))}
</div>
);
export default StoryList;
The error is specifically at line 4 of that, on the first div tag.
Here is my index page:
import React from 'react';
import fetch from 'isomorphic-fetch';
import Error from 'next/error';
import StoryList from '../components/StoryList';
class Index extends React.Component {
static async getInitialProps() {
let stories;
try {
const response = await fetch(
'https://node-hnapi.herokuapp.com/news?page=1'
);
stories = await response.json();
} catch (err) {
console.log(err);
stories = []
}
return { stories };
}
render() {
const { stories } = this.props;
if (stories.length === 0) {
return <Error statusCode={503} />;
}
return (
<div>
<h1>Hacker News Clone</h1>
<StoryList storeis={stories} />
</div>
)
}
}
export default Index;
you have used storeis prop and using as stories
see this,
<div>
<h1>Hacker News Clone</h1>
<StoryList storeis={stories} /> // here prop is storeis
</div>
and used as this,
const StoryList = ({ stories }) => ( // and here using as stories
<div>
{stories.map(story => (
<h3 key={story.id}>{story.title}</h3>
))}
</div>
);
make both same.
I feel that was spell mistake.

Server side load a global component with Next.js in React

The fact that I can't find anyone asking this question probably means that I'm not understanding something fully or I'm searching with the wrong keywords so please don't bite my head off if this is a stupid question.
I'm pasting the relevant parts of the code but if you want a repo of the full example, here it is. The full question will be at the bottom.
Here's my folder structure:
server.js
/components
Layout.js
/pages
contact.js
server.js
// tells next which page to load
server.get("/contact/:id", (req, res) => {
const actualPage = "/contact"
const queryParams = {id: req.params.id}
app.render(req, res, actualPage, queryParams)
})
// api uri for grabbing contacts from the database
server.get("/api/contact/:id", (req, res) => {
Contact.findOne({first_name: req.params.id}, (error, contact) => {
if (error) return next(error)
res.status(200).json(contact)
})
})
pages/contact.js
const Contact = props => (
<Layout>
<h1>{props.contact.first_name} {props.contact.last_name}</h1>
</Layout>
)
// a static async call passes fetched data into the props
Contact.getInitialProps = async function (context) {
const {id} = context.query
const res = await fetch(`http://localhost:3000/api/contact/${id}`)
const contact = await res.json()
return {contact: contact}
}
components/Layout.js
const Layout = (props) =>
<div>
<div>
<Link href="/contact/John">
<a>John</a>
</Link>
<Link href="/contact/Jed">
<a>Jed</a>
</Link>
<Link href="/contact/Fred">
<a>Fred</a>
</Link>
</div>
{props.children}
</div>
I'm trying to figure out whether or not it's possible to dynamically query the database to build a navigation of the documents in the database. The only way I can think to do it is by re-rendering the entire navigation with every component but this seems extremely unnecessary. Again, if you want to give the code a try, here's my example repo.
One of the ways I can think of is to use custom app.js and add componentDidMount method (it is fired only once) where you can fetch all the contacts, store it inside app.js state and pass it down to pages and components.
_app.js
import React from 'react';
import App, { Container } from 'next/app';
export default class MyApp extends App {
static async getInitialProps({ Component, router, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
}
// store contacts in the state
state = {
contacts: undefined
};
componentDidMount() {
// get contacts and store them in the _app.js state
fetch('some-api/all-contacts-endpoint').then(contacts => {
this.setState({ contacts });
});
}
render() {
const { Component, pageProps } = this.props;
return (
<Container>
<Component {...pageProps} contacts={this.state.contacts} />
</Container>
);
}
}
pages/contact.js
// contacts will be inside props here
const Contact = props => (
<Layout contacts={props.contacts}>
<h1>
{props.contact.first_name} {props.contact.last_name}
</h1>
</Layout>
);
// a static async call passes fetched data into the props
Contact.getInitialProps = async function(context) {
const { id } = context.query;
const res = await fetch(`http://localhost:3000/api/contact/${id}`);
const contact = await res.json();
return { contact: contact };
};
components/Layout.js
const Layout = ({ contacts = [] }) => (
<div>
<div>
{contacts.map(contact => (
<Link key={contact.id} href={`/contact/${contact.id}`}>
<a>{contact.name}</a>
</Link>
))}
</div>
{props.children}
</div>
);
Hope this helps!

Fetch data from API depending on the components props

I have problems figuring out how to setup the structure where to the fetch data depending on what the props.catergory value is in my PodcastList component and set state
I could fetch the data in my parent component (Home.js), set the state and pass the state as props. But the API endpoint need to take in an categoryId, I cant fetch all podcasts at once.. Thats why I made a child component that takes in and categoryId. Like this:
<PodcastList category='1301' />
And my tought was to do the fetch in the child component passing this.props.category to the api endpoint. (I accutally dont know what im doing)
Can someone help explain how to accomplish what I want?
My code looks like this:
Home.js component:
import React, { Component } from 'react'
import { fetchPopularPodcasts } from './api'
import PodcastList from './PodcastList'
export default class Home extends Component {
render() {
return (
<div className='container'>
<PodcastList category='1301' /> // Lists all Podcasts from category: Arts
<PodcastList category='1303' /> // Lists all Podcasts from category: Comedy
<PodcastList category='1304' /> // Lists all Podcasts from category: Educationrts
<PodcastList category='1305' /> // Lists all Podcasts from category: Kids & Family
</div>
);
}
PodcastList.js component
import React from 'react'
import { fetchPodcastCategory } from './api'
export default class PodcastList extends Component {
state = {
podcasts: [],
loading: true,
}
async componentDidMount () {
const podcasts = await fetchPodcastCategory(this.props.categoryId);
this.setState({
podcasts,
loading: false,
})
}
render() {
return (
<div className='row'>
<div className='col-md-12'>
{category.map((pod) => {
return (
<div className='pod-box'>
{pod.Title}
{pod.Label}
</div>
)
})}
</div>
</div>
)
}
}
export default PodcastList;
Api.js
import Feed from 'feed-to-json-promise'
export async function fetchPopularPodcasts () {
const response = await fetch('https://itunes.apple.com/search?term=podcast&country=se&media=podcast&entity=podcast&limit=200')
const podcasts = await response.json()
return podcasts.results
}
export async function fetchPodcastCategory (categoryId) {
const response = await fetch(`https://itunes.apple.com/se/rss/toppodcasts/limit=100/genre=${categoryId}/explicit=true/json`)
const podcasts = await response.json()
return podcasts.feed
}
export async function fetchPodcast (podId) {
const response = await fetch(`https://itunes.apple.com/lookup?id=${podId}&country=se`)
const podcasts = await response.json()
return podcasts.results
}
export async function fetchPodcastEpisodes (feedUrl) {
const feed = new Feed()
const episodes = await feed.load(feedUrl)
return episodes
}
I would do that inside podcastlist component, if you want data back to parent component you can run a callback,
give a function to podcastlist as a prop and run that function like this,
const podcasts = await fetchPodcastCategory(this.props.categoryId);
this.setState({
podcasts,
loading: false,
},this.props.callback(podcasts))
}
I don't think your design is all too bad.
Basically if you change
{category.map((pod) => {
with
{this.state.podcasts.map((pod) => {
this code should work.
What are you trying to accomplish exactly and why is this architecture not doing it for you? If you clarify this you can get a better answer.

Categories