FetchError: invalid json response body , reason: Unexpected token < in JSON at position 0 - javascript

i am trying to show up the single blog page in my next project.
i get the error at getStaticProps
i tried make the data that is coming from the api an array but it doesn't work also , i don't know where the issue of this code everything looks fine
i don't know if the error from the api or something else.
import { useRouter } from 'next/router';
import Link from 'next/link';
import BlogsStyle from '../../../styles/Blogs.module.css';
import { Image } from "react-bootstrap";
const Blog = ({ blog }) => {
const router = useRouter()
const {id} = router.query
return (
<div>
<div className={BlogsStyle.blogItem}>
<div className={BlogsStyle.blogImg}>
<Image className={BlogsStyle.blogImgSrc} src={blog.image_url} alt="image blog" onError={(e)=>{e.target.onerror = null; e.target.src="../../public/images/default_blog.png"}} fluid />
</div>
<div className=" blog__item--text">
<div className="info">
<div className="date">{blog.publish_date}</div>
<h6>{blog.title.ar}</h6>
<p>{strip(blog.content.ar).substring(0,100)}</p>
</div>
</div>
</div>
</div>
)
}
export const getStaticPaths = async () => {
const res = await fetch('https://masahefapi.slsal.co/pgarticles/articles/0/10');
const data = await res.json();
console.log(data);
const paths = await data.map(blog =>{
return {
params: { id: blog.id.toString() }
}
})
return {
paths,
fallback: false
}
}
export const getStaticProps = async({ params }) => {
const id = context.params.id;
const res = await fetch(`https://masahefapi.slsal.co/pgarticles/articles/0/10/${params.id}`);
const data = await res.json();
console.log(data);
return {
props: {
blog: data
}
}
}
export default Blog

Related

How do I pass two (or more) API props to a NextJs Page?

I'm trying to render a page with two props from different API fetches.
The adress bar looks like this: http://localhost:3000/startpage?id=1
And the code looks like this, with the first API fetch:
import { useRouter } from "next/router";
export const getServerSideProps = async (context) => {
const { id } = context.query;
const res = await fetch(`${process.env.BACKEND_URL}/User/${id}`);
const data = await res.json();
// console.log(data);
return {
props: { user: data },
};
};
Second API fetch looks like this
export const getServerSideProps2 = async (context) => {
const { id } = context.query;
const res = await fetch(`${process.env.BACKEND_URL}/User/${id}/favorites`);
const data = await res.json();
//console.log(data);
return {
props: { favorites: data },
};
};
And the page that I am trying to render then looks like this:
function StartPage( {user, favorites} ){
return (
<div>
<div className={styles.formGroup}>
<h1>Welcome {user.name}</h1>
</div>
<div>
<h1>These are your favorite movies:</h1>
{favorites.map(favorite => (
<div key={favorite.id}>
<h5>favorite.name</h5>
</div>
))}
</div>
</div>
)
}
I'm guessing that there's a way to put both API fetches in the same function. But I don't know how to. If anyone has any suggetions on how to do that I'd be happy to listen.
Thank you in advance.
You can make the calls in the same method and pass both data:
export const getServerSideProps = async (context) => {
const { id } = context.query;
const res = await fetch(`${process.env.BACKEND_URL}/User/${id}`);
const data = await res.json();
const resFav = await fetch(`${process.env.BACKEND_URL}/User/${id}/favorites`);
const dataFav = await resFav.json();
return {
props: { user: data, favorites: dataFav },
};
};
No need to declare getServerSideProps2

Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. - useEffect()

I get this error when I try and call a function I have imported within my useEffect() hook in Dashboard.jsx. I am just trying to pull in data from database on the page load pretty much so that when user click button they can send off correct credentials to the api.
I am pulling it in from database for security reasons, so client id is not baked into the code.
I am pretty sure that I am getting this error maybe because the function is not inside a react component? although I am not 100% sure. And if that is the case I am not sure of the best way to restructure my code and get the desired output.
Code below.
mavenlinkCredentials.js
import { doc, getDoc } from "firebase/firestore";
import { useContext } from "react";
import { AppContext } from "../../context/context";
import { db } from "../../firebase";
const GetMavenlinkClientId = async () => {
const {setMavenlinkClientId} = useContext(AppContext)
const mavenlinkRef = doc(db, 'mavenlink', 'application_id');
const mavenlinkDocSnap = await getDoc(mavenlinkRef)
if(mavenlinkDocSnap.exists()){
console.log("mavenlink id: ", mavenlinkDocSnap.data());
console.log(mavenlinkDocSnap.data()['mavenlinkAccessToken'])
setMavenlinkClientId(mavenlinkDocSnap.data()['application_id'])
} else {
console.log("No doc");
}
}
export default GetMavenlinkClientId;
Dashboard.jsx
import React, { useContext, useEffect, useState } from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { useNavigate } from "react-router-dom";
import { query, collection, getDocs, where, setDoc, doc, getDoc } from "firebase/firestore";
import { auth, db, logout } from "../firebase";
import { Button, Container, Grid, Paper } from "#mui/material";
import ListDividers from "../components/ListDividers";
import { AppContext } from "../context/context";
import axios from "axios";
import {SuccessSnackbar, ErrorSnackbar} from '../components/PopupSnackbar';
import GetMavenlinkClientId from "../helpers/firebase/mavenlinkCredentials";
const Dashboard = () => {
const [user, loading, error] = useAuthState(auth);
const [name, setName] = useState("");
const [ accessToken, setAccessToken ] = useState("")
const [errorAlert, setErrorAlert] = useState(false);
const [successAlert, setSuccessAlert] = useState(false);
const [mavenlinkClientId, setMavenlinkClientId] = useState("");
const {isAuthenticated} = useContext(AppContext);
const navigate = useNavigate();
const uid = user.uid
const parsedUrl = new URL(window.location.href)
const userTokenCode = parsedUrl.searchParams.get("code");
const { mavenlinkConnected, setMavenlinkConnected } = useContext(AppContext)
const { maconomyConnected, setMaconomyConnected } = useContext(AppContext)
const { bambooConnected, setBambooConnected } = useContext(AppContext)
const fetchUserName = async () => {
try {
const q = query(collection(db, "users"), where("uid", "==", user?.uid));
const doc = await getDocs(q);
const data = doc.docs[0].data();
setName(data.name);
} catch (err) {
console.error(err);
alert("An error occured while fetching user data");
}
};
//
useEffect(() => {
if (loading) return;
if (!user) return navigate("/");
fetchUserName();
if(userTokenCode !== null){
authorizeMavenlink();
}
if(isAuthenticated){
GetMavenlinkClientId()
}
}, [user, loading]);
///put this into a page load (use effect maybe) so user does not need to press button to connect to apis
const authorizeMavenlink = () => {
console.log(uid);
const userRef = doc(db, 'users', uid);
axios({
//swap out localhost and store in variable like apitool
method: 'post',
url: 'http://localhost:5000/oauth/mavenlink?code='+userTokenCode,
data: {}
})
.then((response) => {
setAccessToken(response.data);
setDoc(userRef, { mavenlinkAccessToken: response.data}, { merge: true });
setMavenlinkConnected(true);
setSuccessAlert(true);
})
.catch((error) => {
console.log(error);
setErrorAlert(true)
});
}
//abstract out client id and pull in from db
const getMavenlinkAuthorization = () => {
window.open('https://app.mavenlink.com/oauth/authorize?client_id='+mavenlinkClientId+'&response_type=code&redirect_uri=http://localhost:3000');
window.close();
}
const authorizeBamboo = () => {
axios({
method: 'get',
url: 'http://localhost:5000/oauth/bamboo',
data: {}
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error);
});
// console.log('bamboo connected')
setBambooConnected(true);
}
const authorizeMaconomy = () => {
console.log("Maconomy connected")
setMaconomyConnected(true);
}
const syncAccount = async() => {
if(!mavenlinkConnected){
await getMavenlinkAuthorization()
}
if (!bambooConnected){
await authorizeBamboo();
}
if (!maconomyConnected){
await authorizeMaconomy();
}
}
const handleAlertClose = (event, reason) => {
if (reason === 'clickaway') {
return;
}
setSuccessAlert(false) && setErrorAlert(false);
};
console.log(mavenlinkClientId);
return(
<>
<Container>
<div className="dashboard">
<h1>Dashboard</h1>
<Grid container spacing={2}>
<Grid item xs={12}>
<Paper style={{paddingLeft: "120px", paddingRight: "120px"}} elevation={1}>
<div className="dashboard-welcome">
<h2>Welcome {name}</h2>
<h4>{user?.email}</h4>
<hr/>
<h2>Integrations</h2>
<Button onClick={syncAccount}>
Sync Account
</Button>
{/* <Button onClick={getMavenlinkClientId}>
Bamboo Test
</Button> */}
<ListDividers/>
</div>
</Paper>
</Grid>
</Grid>
</div>
{successAlert === true ? <SuccessSnackbar open={successAlert} handleClose={handleAlertClose}/> : <></> }
{errorAlert === true ? <ErrorSnackbar open={errorAlert} handleClose={handleAlertClose}/> : <></> }
</Container>
</>
);
}
export default Dashboard;
the error is because you’re calling const {setMavenlinkClientId} = useContext(AppContext) inside the file mavenlinkCredentials.js which is not a react components.
you could maybe change the function inside mavenlinkCredentials.js to accept a setMavenlinkClientId and pass it from outside like this.
const GetMavenlinkClientId = async (setMavenlinkClientId) => {
const mavenlinkRef = doc(db, 'mavenlink', 'application_id');
const mavenlinkDocSnap = await getDoc(mavenlinkRef)
if(mavenlinkDocSnap.exists()){
console.log("mavenlink id: ", mavenlinkDocSnap.data());
console.log(mavenlinkDocSnap.data()['mavenlinkAccessToken'])
setMavenlinkClientId(mavenlinkDocSnap.data()['application_id'])
} else {
console.log("No doc");
}
}
and then you can call this function in your dashboard.js like so,
const {setMavenlinkClientId} = useContext(AppContext)
if(isAuthenticated){
GetMavenlinkClientId(setMavenlinkClientId)
}

Next JS [id] error Error serializing `.data` returned from `getServerSideProps` in "/services/[id]"

I make Next JS project and I am new to coding in this program and have a "Service" folder. In this folder there are index.js and [id].js (details page). All data come from Next API. Index.js works, there is no problem. But when I click the details element the error is seen. I don't know what is my mistake
Error: Error serializing `.data` returned from `getServerSideProps` in "/services/[id]". Reason: `object` ("[object Promise]") cannot be serialized as JSON. Please only return JSON serializable data types.
index.js
<section className="services-main">
<div className="services-main-context container">
<MainPageServices posts={posts} />
</div>
</section>
....
export async function getStaticProps() {
const res = await fetch("http://localhost:3000/api/servicesApi/");
const posts = await res.json();
return {
props: {
posts,
},
};
}
MainPageServices component
<div className="main-page-services-cards">
{posts.map((card, key) => (
<div key={card.id} className="service-card">
<Link href={`/services/${card.id}`}>
<a>
<div className="card-img">
<Image src={card.img} alt="Services" />
</div>
</a>
</Link>
</div>
))}
</div>
Not working component (Details)
const ServiceDetails = ({ data }) => {
console.log(data);
return (
<h1>{data.header}</h1>)
);
};
export const getServerSideProps = async (context) => {
const res = await fetch(`http://localhost:3000/api/servicesApi/${context.params.id}`);
const data = res.json();
return {
props: {
data,
},
};
};
My details page API
import { servicesData } from "../../../data";
export default function handler(req, res) {
const { id } = req.query;
const service = servicesData.find((service) => service.id === parseInt(id));
res.status(200).json(service);
}
I think you need to await res.json() because your error says you are passing a promise into your props.
const ServiceDetails = ({ data }) => {
console.log(data);
return (
<h1>{data.header}</h1>)
);
};
export const getServerSideProps = async (context) => {
const res = await fetch(`http://localhost:3000/api/servicesApi/${context.params.id}`);
const data = await res.json();
return {
props: {
data,
},
};
};

Cannot display Fetched data to the UI in React

it doesn't show an error and the project works just fine. I can log the data to the console as well. but it doesn't display in the UI. this is a tutorial project on youtube
I'm getting data from the API and passing that to the tours and tour components. and Tour component displays the fetched data.
App component
import React, { useState, useEffect } from "react";
import Loading from "./Loading";
import Tours from "./Tours";
// ATTENTION!!!!!!!!!!
// I SWITCHED TO PERMANENT DOMAIN
const url = "https://course-api.com/react-tours-project";
function App() {
const [loading, setLoading] = useState(true);
const [tours, setTours] = useState([]);
const fetchTours = async () => {
try {
const response = await fetch(url);
const tours = await response.json();
setLoading(false);
setTours(tours);
} catch (error) {
setLoading(true);
console.log(error);
}
};
useEffect(() => {
fetchTours();
}, []);
if (loading) {
return (
<main>
<Loading />
</main>
);
}
return (
<main>
<Tours tours={tours} />
</main>
);
}
export default App;
Tours component
import React from "react";
import Tour from "./Tour";
const Tours = ({ tours }) => {
return (
<section>
<div className="title">
<h2>Our Tours</h2>
<div className="underline"></div>
</div>
<div>
{tours.map((tour, index) => {
return <Tour key={tour.id} {...tours} />;
})}
</div>
</section>
);
};
export default Tours;
Tour Component
import React, { useState } from "react";
const Tour = ({ id, image, info, price, name }) => {
return (
<article className="single-tour">
<img src={image} alt={name} />
<footer>
<div className="tour-info">
<h4>{name}</h4>
<h4 className="tour-price">AUD{price}</h4>
</div>
<p>{info}</p>
<button className="delete-btn">Not Interested</button>
</footer>
</article>
);
};
export default Tour;
Try this code:
useEffect(async () => {
await fetchTours();
}, []);
I think your UI has not updated after the data arrived. You need to wait for your data is fetched.
Try to remove the setting of state in the function and move it to use effect. Have the API call only return the list instead of having it retrieving the list and setting the state.
const fetchTours = async () => {
const response = await fetch(url);
const tours = await response.json();
return tours;
};
useEffect(() => {
const fetchAndSetTourState = async () => {
const data = await fetchTours();
setTours(data);
setLoading(false);
}
fetchAndSetTourState();
}}, []);

Fetching translations based on language header with axios isn't working

I'm trying to build website consist of one page containing many components.
I want to fetch data for each component
so I try use Promise.all() in index page
but the problem is that translations from API don't appear only one language appears.
I used Next.js Internationalized Routing,
but when I only make axios.get() for one component it works.
What is the problem & how can I solve that?
header.js
import Link from 'next/link';
import { useRouter } from 'next/router';
import en from './locales/en';
import ar from './locales/ar';
import Axios from 'axios';
import Cookie from 'js-cookie';
import {useState } from 'react';
const Header = () => {
const router = useRouter();
const [langCode, setLangCode] = useState('en');
Axios.defaults.headers.common['Language'] = langCode;
const { locale } = router;
const t = locale === 'en' ? en : ar;
const changeLanguage = (locale) => {
Cookie.set('lang', locale);
router.push(router.pathname, router.asPath, { locale });
setLangCode(locale);
};
const lang = Cookie.get('lang')
return (
<header>
<button onClick={() => changeLanguage(lang == 'en' ? 'ar' : 'en')}>
change lang
</button>
<ul>
<li>
<Link href="/">
<a>{t.home}</a>
</Link>
</li>
</ul>
</header>
);
};
export default Header;
index.js
import Axios from "axios";
import Header from "../components/Header";
const index = ({ data }) => {
return (
<div>
<Header />
<div dangerouslySetInnerHTML={{ __html: data.details}}/>
</div>
);
};
index.getInitialProps = async () => {
const res = await Axios.get(`https://api.trueapps.co/api/who-we-are`);
const data = await res.data.data;
return { data };
};
export default index;
AND this is the code in index.js when I use Promise.all().
index.js
import Axios from "axios";
import Header from "../components/Header";
const index = (data) => {
console.log(data.about);
console.log(data.services);
console.log(data.team);
return (
<div>
<Header />
</div>
);
};
index.getInitialProps = async () => {
const [about, team, services] = await Promise.all([
fetch(`https://api.trueapps.co/api/who-we-are`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/team`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/services`).then((r) => r.json()),
]);
return { about, team, services};
};
export default index;
The issue is that you're setting the default Language header in axios (Axios.defaults.headers.common['Language'] = langCode;) but then making the requests using fetch.
Using axios to make the requests in index.getInitialProps should do the trick.
index.getInitialProps = async () => {
const [aboutRes, teamRes, servicesRes] = await Promise.all([
Axios.get(`https://api.trueapps.co/api/who-we-are`),
Axios.get(`https://api.trueapps.co/api/team`),
Axios.get(`https://api.trueapps.co/api/services`)
]);
return {
about: aboutRes.data,
team: teamRes.data,
services: servicesRes.data
};
};
Looks like you are mixing Axios and fetch API together. Maybe you need to change to Axios's get instead of fetch API from the below code.
index.getInitialProps = async () => {
const [about, team, services] = await Axios.all([
await fetch(`https://api.trueapps.co/api/who-we-are`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/team`).then((r) => r.json()),
fetch(`https://api.trueapps.co/api/services`).then((r) => r.json()),
]);
return { about, team, services};
};

Categories

Resources