NextJs - load dynamic data to the main page from different file - reactjs

I am trying to add dynamic data from one file to another and am having issues with that.
The data I am trying to load from
path: /src/components/Subnav.js
import React, { Component } from "react";
class Subnav extends Component {
static async getInitialProps(ctx) {
const res = await fetch("https://api.github.com/repos/vercel/next.js");
const json = await res.json();
return { stars: json.stargazers_count };
}
render() {
return <div>Next stars: {this.props.stars}</div>;
}
}
export default Subnav;
The code where I want the above data in
import React from "react";
import Subnav from "../src/components/Subnav";
function Page({ json }) {
return (
<subNav />
)
}
output in the browser
<div>Next stars: </div>
The expected output in the browser
<div>Next stars: 88542</div>
Issue:
As you can see above, I am just seeing the static text which is "Next stars" however, i am not seeing the data from the JSON

getInitialProps is data fetching method for page, it means you only can use it inside /pages folder. If you want fetching data for components, you can use useEffect.
import React, { useEffect, useState } from "react";
const Subnav = () => {
const [stars, setStars] = useState(null);
useEffect(() => {
const getStars = async () => {
const res = await fetch("https://api.github.com/repos/vercel/next.js");
const json = await res.json();
setStars(json.stargazers_count)
}
getStars();
}, [])
return <div>Next stars: {stars}</div>
}
export default Subnav;

Related

Failing to read data from firebase firestore using next.js getStaticProps

I am trying to read data from firebase using nextjs but I get back an empty page. Even when I console log, nothing gets returned. This is how my code looks like
import React, {useState} from 'react'
import { db } from '../firebase'
import { collection, getDocs } from "firebase/firestore";
const reference = collection(db, "students");
function Card(props) {
const { studentsData } = props
return (
<div>
<p>This is just a test</p>
{studentsData && studentsData.map(students => (
<p>{students.name}</p>
))}
</div>
)
}
export const getStaticProps = async () => {
const students = await getDocs(reference);
const studentsData = students.docs.map(doc => ({id: doc.id, ...doc.data() }))
console.log(studentsData);
return {
props: { studentsData }
}
}
export default Card
All I get back from this is just an empty page. Where could I be going wrong?.

The problem is the contract methods are working in class based components but not in functional based components. In next or react js both .why?

//This one is not working .it gives and error that module.methods.getdeployedContracts().call() is //not a function/
import factory from "../ethereum/factory";
import { Component } from "react";
function Home({ campaigns }) {
console.log(campaigns);
return <div>{campaigns[0]}</div>;
}
Home.getInitialProps = async () => {
const res = await factory.methods.getDeployedContracts().call();
return { campaigns: res };
};
export default Home;
// But when i change it to a class based componet it works //
import factory from "../ethereum/factory";
import { Component } from "react";
class Home extends Component {
static async getInitialProps() {
const campaigns = await factory.methods.getDeployedCampaigns().call();
return { campaigns };
}
render() {
const { campaigns } = this.props;
console.log("campaigns", campaigns);
return (
<div>
<h3>{this.props.campaigns[0]}</h3>
</div>
);
}
}
export default Home;
enter image description here
Check your functional component code.
function Home({ campaigns }) {
console.log(campaigns);
return <div>campaigns</div>; ---- Here is the problem
}
Home.getInitialProps = async () => {
const res = await factory.methods.getDeployedContracts().call();
return { campaigns: res };
};
You are just using campaigns as a text and rendering inside the div but you want to use that as a variable. Just do like how you are using it in the class component.
return <div>{campaigns}</div>;
That'll print whatever the value stored in the campaigns. If it's an array, iterate it and print its elements.

NextJs: get server side props internal server problem with axios

Hello im going to get data from API using this https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
but I'm using Axios instead of default like doc, same as the doc passing data through the props, already implement this but instead return data its return 500 internal server which is it works when on the localhost.
this is my home.js
import axios from "axios";
import Featured from "../components/Featured";
import ProductList from "../components/ProductList";
import styles from "../styles/Home.module.css";
export default function Home({ productList }) {
return (
<div className={styles.container}>
<Featured />
<ProductList productList={productList} />
</div>
);
}
export const getServerSideProps = async () => {
const res = await axios.get(
"http://localhost:3000/api/products" ||
"https://marrs-id.vercel.app/api/products"
);
const data = await res.data;
return {
props: {
productList: data,
},
};
};
am I missing something here?
You might want to store your API path in a .env file at the root of your project. So it can be used everywhere in your app and easy to maintain ?
Also I guess you can use Fetch instead of Axios for this case, something like this :
export const getServerSideProps = async () => {
const productListRes = await fetch(
`${process.env.API_ROOT}/api/products`
);
const productList = await productListRes.json();
return {
props: {
productList,
},
};
};

Send param to fetch in getInitialProps react and nextjs

I 'm traying to send a param to getInitialProp function to made the fecth to the correct json.
here is my code:
hepler.js --> here I made the fetch per se.
export async function getEvents() {
const res = await fetch("https://url/eventos.json");
let new_data = await res.json();
return { events: new_data.data };
}
export async function getDetails(slug) {
const res = await fetch(`https://myurl/${slug}.json`);
let data_detail_event = await res.json();
return { data_detail_event };
}
_app.js // here I have the getInitialProps and works great
import App from "next/app";
import ContextProvider from "../provider/ContextProvider";
import fetch from "isomorphic-unfetch";
import {getEvents, getDetails} from '../helper/index'
export default class MyApp extends App {
static async getInitialProps() {
const events = await getEvents();
return {
events : events.events
};
}
render() {
const { Component, pageProps } = this.props;
return (
<div>
<ContextProvider events={this.props.events} >
<Component {...pageProps} />
</ContextProvider>
</div>
);
}
}
pages/[id].js
import { useRouter } from "next/router";
import Context from "../../config/Context";
/* Components */
import WordCounter from "../../components/word-counter/WordCounter";
function Post(props) {
const router = useRouter();
const context = React.useContext(Context);
return (
<React.Fragment>
<WordCounter />
</React.Fragment>
);
}
Post.getInitialProps = async ({ query}) => {
const detail = await getDetail(query.id) --> here I send the param and it seems never arrive to helper.js, why?
return {detail}
}
export default Post
Where is the problem? HELP!
THAANKS!
i think getInitialProps run in server and your helper function doesn't load there.
use fetch inside getInitialProps .

How to call GraphQL outside a component

I have made a bunch of React component calling GraphQL using the Query component and everything is working fine.
In one component I need to have some initial data from the database, but without any visual representation.
I have tried to use the query component but it seems to be triggered only on the render cycle. I have tried to package it into a function and call this function in the component that needs the data. But the code / query is not executed since there's no component to show.
How do I go about getting this data from the database without a component?
I can't find any documentation on how to solve this problem. But I can't be
the only one doing this.
Is ApolloConsumer or ApolloProvider the answer to my problems?
I'm working with conferences and sessions. A conference runs over a couple of days and each day has a number of sessions.
What I'm trying to achieve is to render a page with X numbers of tabs one for each day. Each tab represents a day and it shows the number of sessions for the day.
My sessions page:
import React from 'react';
import FullWidthTabs from '../components/Sessions';
import SessionTab from '../components/SessionTab';
import BwAppBar2 from '../components/BwAppBar2';
import ConferenceDays from '../components/ConferenceDays';
class SessionsPage extends React.Component {
static async getInitialProps() {
console.log("GetInitProps SessionsPage");
}
render() {
let a = ConferenceDays();
return (
<div>
<BwAppBar2 />
{a}
<FullWidthTabs days={['2018-06-11', '2018-06-12', '2018-06-13']} day1={ < SessionTab conferenceId = "57" day = '2018-06-11' / > }
day2={ < SessionTab conferenceId = "57" day = '2018-06-12' / > } day3={ < SessionTab conferenceId = "57" day = '2018-06-13' / > }>
</FullWidthTabs>
</div>
);
}
}
export default (SessionsPage);
Here the dates have been hardcoded in the page just for testing.
But order to know how many days the conference spans i'll have to find the conference and decide the start and end date and generate all the dates in between:
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Query } from 'react-apollo'
import gql from 'graphql-tag'
import Link from '#material-ui/core/Link';
import { useQuery } from "react-apollo-hooks";
import conferencesQuery from '../queries/conferences'
import { Table, Head, Cell } from './Table'
import ConferenceCard from './ConferenceCard';
import Grid from '#material-ui/core/Grid';
import Paper from '#material-ui/core/Paper';
import moment from 'moment';
const CONFERENCE_QUERY = gql`
query conference($conferenceId : ID!){
conference(id: $conferenceId){
title
start_date
end_date
}
}
`
let index = 0;
let loopDate = 0;
let dates = [];
let conferenceId = 57;
const ConferenceDays = () => (
<Query query={CONFERENCE_QUERY} variables={{conferenceId}}>
{({ loading, error, data }) => {
if (loading)
return <div>Fetching</div>
if (error)
return <div>Error</div>
const startDate = moment(data.conference.start_date, 'x');
const endDate = moment(data.conference.end_date, 'x');
for (loopDate = parseInt(data.conference.start_date);
loopDate < parseInt(data.conference.end_date);
loopDate += 86400000) {
let aDate = moment(loopDate, 'x');
dates.push(aDate.format('YYYY-MM-DD').toString());
}
console.log(dates);
return(dates);
}}
</Query>);
export default ConferenceDays
But is this approach incorrect?
Would it be more correct to lift the ConferenceDates component up in the hierarchy?
Kim
You could separate the creation of the ApolloClient to a separate file and use an init function to access the client outside of React components.
import React from 'react';
import {
ApolloClient,
HttpLink,
InMemoryCache,
} from "#apollo/client";
let apolloClient;
const httpLink = new HttpLink({
uri: "http://localhost:4000/graphql",
credentials: "same-origin",
});
function createApolloClient() {
return new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
}
export function initializeApollo() {
const _apolloClient = apolloClient ?? createApolloClient();
if (!apolloClient) apolloClient = _apolloClient;
return _apolloClient;
}
export function useApollo() {
const store = useMemo(() => initializeApollo(initialState), [initialState]);
return store;
}
Then you would use this outside components like this:
const client = initializeApollo()
const res = await client.query({
query: MY_QUERY,
variables: {},
})
I didn't try this myself, but I think this you an idea on how to go about this and how to access the ApolloClient.
If you are using functional components, you can use useApolloClient hook in a function as though it is not a hook.
import { useApolloClient, gql } from "#apollo/client";
MY_QUERY = gql'
query OUR_QUERY {
books{
edges{
node{
id
title
author
}
}
}
}
'
const myFunctionalComponent = () => { // outside function component
const client = useApolloClient();
const aNormalFunction = () => { // please note that this is not a component
client.query({
query: MY_QUERY,
fetchPolicy: "cache-first" // select appropriate fetchPolicy
}).then((data) => {
console.log(data) //do whatever you like with the data
}).catch((err) => {
console.log(err)
})
};
// just call it as a function whenever you want
aNormalFunction()
// you can even call it conditionally which is not possible with useQuery hook
if (true) {
aNormalFunction()
}
return (
<p>Hello Hook!</>
);
};
export default myFunctionalComponent;
ApolloClient has a mutate method. You can just import your Apollo client instance and call apolloClient.mutate.
From a React component you can use useLazyQuery from Apollo Client which will only fire when you call it. Then pass it to your function and call it there.
For people using urql as GraphQL client-
const graphqlClient = createClient({
url: '',
fetchOptions: () => {
return {
headers: { }
};
}
});
const fetchCountries = () => (dispatch: Dispatch) => {
graphqlClient
.query(countriesQuery, getCountriesVariable())
.toPromise()
.then(result => {
dispatch({
type: UPDATE_COUNTRIES,
payload: result.data.countries
});
if (result.error?.message) {
// https://formidable.com/open-source/urql/docs/basics/errors/
logErrorMessage(result.error?.message, 'AppActions.fetchCountries');
}
})
.catch(error => {
logError(error, 'AppActions.fetchCountries');
});
};
Docs: https://formidable.com/open-source/urql/docs/api/core/#clientquery

Resources