Displaying data from SWAPI - next.js

I am trying to display film details from this API https://swapi.dev/api/films in NextJS but I keep getting an error. It has something to do with the getStaticPath function. I am using this code: any help welcome.
import fetch from 'isomorphic-unfetch';
export const getStaticPaths = async () => {
const res = await fetch('https://swapi.dev/api/films');
const data = await res.json();
console.log("This is " + JSON.stringify(data));
const paths = data.results.map(film => {
return {
params: { id: film.episode_id.toString() },
};
});
return {
paths,
fallback: false,
};
};
export const getStaticProps = async (context) => {
const id = context.params.id;
const res = await fetch(`https://swapi.dev/api/films` + id);
const data = await res.json();
return {
props: { film: data },
};
};
const Details = ({ film }) => {
return (
<div>
<h1>Episode {film.episode_id}</h1>
<h1>{film.title}</h1>
</div>
);
};
export default Details;
I am expecting the episode ID and title to display
enter image description here
I have tried taking 'results' out of 'data.results.map', so 'data.map' but just results in a error says data.map is not a function...I guess because data is an object not an array. But results is an array so I am still lost. I do think the issue lies here somewhere though...

Related

Next.js reference error "client" is not defined

I am having an error when trying to fetch product data from sanity with getStaticPaths
here is my code:
import React, { useState } from "react";
function ProductPage({ product, products }) {
const { image, name, details, price } = product;
return (
<div className="pdPage">
<div className="container">{name}</div>
</div>
);
}
export default ProductPage;
export const getStaticPaths = async () => {
const query = `*[_type == "product"] {
slug {
current
}
}
`;
const products = await client.fetch(query);
const paths = products.map((product) => ({
params: {
slug: product.slug.current,
},
}));
return {
paths,
fallback: "blocking",
};
};
export const getStaticProps = async ({ params: { slug } }) => {
const query = `*[_type == "product" && slug.current == '${slug}'][0]`;
const productsQuery = '*[_type == "product"]';
const product = await client.fetch(query);
const products = await client.fetch(productsQuery);
console.log(product);
return {
props: { products, product },
};
};
And then I get reference error client is not defined from getstatic client.fetch
I even delete my code and replace from tutor github repository, but get the same error
After figure it out sometimes I found that I forgot to import client from

Syntax Error: Invalid number, expected digit but got: "t". while passing a slug url to the graphql query function (nextjs app)

I'm having this error while I'm trying to get the right content according to the url. This is my query function:
const getSlugQuery = (slug) => {
const SLUG_QUERY = gql`
query ($slug: String!) {
postCollection(where:{slug:${slug}}) {
items {
title
shortDescription
heroImg {
url
}
createdAt
slug
}
}
}
`;
return SLUG_QUERY;
};
my getStaticprops where I pass the context.params.id:
export const getStaticProps = async (context) => {
const apolloClient = initializeApollo();
const { data } = await apolloClient.query({
query: getSlugQuery(context.params.id)
});
and the getStaticPath to prerender the cases:
export async function getStaticPaths() {
const apolloClient = initializeApollo();
const { data } = await apolloClient.query({
query: POSTS_QUERY
});
const paths = data.postCollection.items.map((post) => ({
params: { id: post.slug },
}))
return { paths, fallback: false }
}
If I try to pass an hardcoded url to the query, the response is working. What am I doing wrong there?
thanks
I believe you need to change your implementation to pass variables
Change getSlugQuery to not take any parameters:
const getSlugQuery = () => {
const SLUG_QUERY = gql`
query ($slug: String!) {
postCollection(where:{slug:$slug}) {
items {
title
shortDescription
heroImg {
url
}
createdAt
slug
}
}
}
`;
return SLUG_QUERY;
};
Then change getStaticProps to pass the slug as a variable to the apolloclient:
export const getStaticProps = async (context) => {
const apolloClient = initializeApollo();
const { data } = await apolloClient.query({
query: getSlugQuery(),
variables: {
slug: context.params.id,
},
});
};

Why is the Redux state not updating with the API data?

I've been following the process for making an API call and storing it in global state with Redux using this project that I got from a Medium article. So far everything seems to work alright, no errors, but when I go to retrieve the global state there is nothing there. It doesn't seem to have been updated by the action that makes the API call. The relevant bits of code are as follows:
in reducers.js:
const initialState = {
mods: [],
pagination: { pageSize: 15, numPages: 1 },
sortFilter: "mostPopular",
};
const globalState = (state = initialState, action) => {
switch (action.type) {
case SET_MOD_LIST:
return { ...state, mods: state.mods };
case SET_MOD_DETAILS:
return { ...state };
default:
return state;
}
};
const rootReducer = combineReducers({
globalState,
});
export default rootReducer;
in actions.js:
export const fetchModList = (pagination, sortFilter = "mostPopular") => {
const { pageSize = 15, numPages = 1 } = pagination ?? {};
return async (dispatch) => {
const response = await fetch(
`https://www.myapi.com/mods?page=${numPages}&pageSize=${pageSize}&sortBy=${sortFilter}`
);
const resData = await response.json();
dispatch({ type: SET_MOD_LIST, mods: resData });
};
};
in index.js (Next.js root page):
const mods = useSelector((state) => state);
const dispatch = useDispatch();
useEffect(() => {
dispatch(fetchModList({pageSize:2}));
}, [dispatch]);
console.log({mods})
This is 100% a result of Redux ignorance, this is my first project using it which I'm doing for an interview. Any help would be much appreciated!
Looks like you're setting mods to its own value mods: state.mods. Did you mean to set a value from action.payload rather than state.mods?

Dynamic Content not loading in NextJs Dynamic Pages

Currently I have a Blogs collection type in my Strapi CMS with an Id and title data fields. I'm using NextJs for my frontend to dynamically load blog content for each blog page. But my content doesn't load when my dynamic page is loaded.
Page where individual blogs are stored:
{posts &&
posts.map((item, idx) => (
<Link href={`/BlogPage/${item.id}`}>
<div>
<img src={`http://localhost:1337${item.Thumbnail.url}`}/>
</div>
</Link>
Then inside my BlogPage directory i have a file [id].js:
export default function name({blog}) {
return (
<>
<div>
{blog.Title}
</div>
</>
)}
// Tell nextjs how many pages are there
export async function getStaticPaths() {
const res = await fetch("http://localhost:1337/blogs");
const posts = await res.json();
const paths = posts.map((blog) => ({
params: { id: blog.id.toString() },
}));
return {
paths,
fallback: false,
};
}
// Get data for each individual page
export async function getStaticProps({ params }) {
const { id } = params;
const res = await fetch(`http://localhost:1337/blogs?id=${id}`);
const data = await res.json();
const posts = data[0];
return {
props: { posts },
};
}
This takes me to this URL http://localhost:3000/BlogPage/1 and gives me an error
TypeError: Cannot read property 'Title' of undefined
Try to out the getStaticProps and getStaticPaths of name function
export async function getStaticPaths() {
const res = await fetch("http://localhost:1337/blogs");
const posts = await res.json();
const paths = posts.map((blog) => ({
params: { id: blog.id.toString() },
}));
return {
paths,
fallback: false,
};
}
export async function getStaticProps({ params }) {
const { id } = params;
const res = await fetch(`http://localhost:1337/blogs?id=${id}`);
const data = await res.json();
const posts = data[0];
return {
props: { posts },
};
}
export default function name({posts }) { // change this line
return (
<>
<div>
{posts.Title} // change this line // Are you sure is it Title? not title? if it is with lowercase, it will return null
</div>
</>
)
}

Dispatch function seems to run more than one time after I test on stand alone app expo-deeplink

It sounds so weird to me and I have no idea what's wrong here because everything is fine in a development environment. So the way app works are simple, user sign in, choose it's therapist then pay for it and after successful payment, booking is confirmed, but the problem is booking is being booked exactly 3 times in firebase real-time database no matter what and I don't know why... (in the development area all is fine and it's gonna book just once as the user requested)
here's my code of booking:
const bookingHandler = () => {
Linking.openURL('http://www.medicalbookingapp.cloudsite.ir/sendPay.php');
}
const handler = (e) => handleOpenUrl(e.url);
useEffect(() => {
Linking.addEventListener('url', handler)
return () => {
Linking.removeEventListener('url', handler);
}
});
const handleOpenUrl = useCallback((url) => {
const route = url.replace(/.*?:\/\/\w*:\w*\/\W/g, '') // exp://.... --> ''
const id = route.split('=')[1]
if (id == 1) {
handleDispatch();
toggleModal();
} else if (id == 0) {
console.log('purchase failed...');
toggleModal();
}
});
const handleDispatch = useCallback(() => {
dispatch(
BookingActions.addBooking(
therapistId,
therapistFirstName,
therapistLastName,
selected.title,
moment(selectedDate).format("YYYY-MMM-DD"),
selected.slots,
)
);
dispatch(
doctorActions.updateTherapists(therapistId, selected.slots, selectedDate, selected.title, selectedPlanIndex, selectedTimeIndex)
);
setBookingConfirm(true)
})
booking action:
export const addBooking = (therapistId, therapistFirstName, therapistLastName, sessionTime, sessionDate, slotTaken) => {
return async (dispatch, getState) => {
let userId = firebase.auth().currentUser.uid
const confirmDate = moment(new Date()).format("ddd DD MMMM YYYY")
const response = await fetch(
`https://mymedicalbooking.firebaseio.com/bookings/${userId}.json`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
userId,
therapistId,
confirmDate,
therapistFirstName,
therapistLastName,
sessionTime,
sessionDate,
slotTaken
})
}
);
if (!response.ok) {
throw new Error('Something went wrong!');
}
const resData = await response.json();
dispatch({
type: ADD_BOOKING,
bookingData: {
userId: userId,
therapistId: therapistId,
therapistFirstName: therapistFirstName,
therapistLastName: therapistLastName,
sessionTime: sessionTime,
sessionDate: sessionDate
}
});
};
};
Booking reducer:
const initialState = {
bookings: [],
userBookings: []
};
export default (state = initialState, action) => {
switch (action.type) {
case ADD_BOOKING:
const newBooking = new Booking(
action.bookingData.id,
action.bookingData.therapistId,
action.bookingData.therapistFirstName,
action.bookingData.therapistLastName,
action.bookingData.bookingdate
);
return {
...state,
bookings: state.bookings.concat(newBooking)
};
case FETCH_BOOKING:
const userBookings = action.userBookings;
return {
...state,
userBookings: userBookings
};
}
return state;
};
also, I use expo, SDK 38, Firebase as a database.
I really need to solve this, please if you have any idea don't hesitate to leave a comment or answer all of them kindly appreciated.
UPDATE:
I commented out all deep linking functionality and test the result, it's all fine. so I think the problem is with the eventListener or how I implemented my deep linking code but I still don't figure out what's wrong with the code that does fine in expo and has a bug in stand-alone.
UPDATE 2
I tried to add dependency array as suggested but still I have same problem..
there is an issue in expo-linking which on the standalone detached android app: event url fires multiple times ISSUE
I just wrapped my handling function in lodash's debounce with 1000ms wait
install lodash like this
yarn add lodash
import _ from 'lodash';
const handleOpenUrl = _.debounce((event) => {
// here is other logic
},1000);
here is your code
just add an empty dependency array into useEffect and use useCallback like this
useEffect(() => {
Linking.addEventListener('url', handleOpenUrl)
return () => {
Linking.removeEventListener('url', handleOpenUrl);
}
},[]); //like this []
const handleOpenUrl = _.debounce((url) => {
const route = url.replace(/.*?:\/\/\w*:\w*\/\W/g, '') // exp://.... --> ''
const id = route.split('=')[1]
if (id == 1) {
handleDispatch();
toggleModal();
} else if (id == 0) {
console.log('purchase failed...');
toggleModal();
}
},1000); //like this []
const handleDispatch = useCallback(() => {
dispatch(
BookingActions.addBooking(
therapistId,
therapistFirstName,
therapistLastName,
selected.title,
moment(selectedDate).format("YYYY-MMM-DD"),
selected.slots,
)
);
dispatch(
doctorActions.updateTherapists(therapistId, selected.slots, selectedDate, selected.title, selectedPlanIndex, selectedTimeIndex)
);
setBookingConfirm(true)
},[selected])

Resources