NextJS change data in API from component - javascript

I've got a problem with updating data from API in NextJS. I want to increment the value by clicking on the button and then update the API.
My local JSON file is in at http:localhost/api/data
data.js:
export default function handler(req, res) {
res.status(200).json({ value: 0 })
}
I want to update this value from Home component
index.js:
import { useState } from 'react'
export default function Home({data) {
const [currentData, setCurrentData] = useState(data)
return (
<div>
{data.value}
<button onClick={(e) => setCurrentData(currentData.value + 1)}>+</button>
</div>
)
}
export async function getServerSideProps() {
const res = await fetch('http://localhost:3000/api/data')
const data = await res.json()
return {
props: { data },
}
}
Is there any way to do it? If something is unclear feel free to ask :)

Related

Axios not fetching data using Reactjs

I am working with Reactjs/nextjs and i am trying to fetch data using "Axios", In "Api url" data is fetching/showing but in my webpage showing "There are no records yet",Where i am wrong ? Here is my current code
import React from 'react'
import { useEffect, useState } from "react";
import axios from 'axios';
function Displaydata() {
const [posts,setPosts]=useState([]);
useEffect(()=>
{
const getdata=async()=>
{
const { data: res } = await axios.get(
"xxxxxxxxxxxxxxxxxxxx/api/Allvideo"
);
console.log(res);
setPosts(res);
};
})
return(
<div>
{posts?.length ? posts.map((product: { id: any; link: any; }) => <p key={product.id}>
{product.id}-{product.link}</p>)
: <h3>There are no records yet</h3>}
</div>
)
}
export default Displaydata
We need to pass second argument for useEffect as empty array or array of values. and then getdata function declared but not called. please find the below code.
useEffect(() => {
const getdata = async() => {
const { data: res } = await axios.get("xxxxxxxxxxxxxxxxxxxx/api/Allvideo");
console.log(res);
setPosts(res);
};
getdata();
}, []);
hope this helps!!!

Can I use 'useSWR' with the contentful-client to create pagination?

I'm trying to create pagination with nextjs and the useSWR hook.
This is how I've currently done it, and it appears to be working... however I read in the docs that the key passed as the first parameter should be a unique string (usually a URL). I'm just passing the index to fetch the correct data. Will my approach mess up the caching? I'm not sure if I'm doing this correctly?
index.js
import React, { useState } from 'react'
import Page from '../components/page'
export default function IndexPage( ) {
const [pageIndex, setPageIndex] = useState(0)
return (
<div>
<Page index={pageIndex} />
<button onClick={() => setPageIndex(pageIndex - 1)}>Previous</button>
<button onClick={() => setPageIndex(pageIndex + 1)}>Next</button>
</div>
)
}
And in my page.js
import useSWR from 'swr'
import { fetcher } from '../client/fetcher'
function Page({ index }) {
const { data } = useSWR(index, fetcher)
console.table(data)
return <div>nothing here, just testing</div>
}
export default Page
And finally the fetcher.js
import client from './contentful-client'
export async function fetcher(pageIndex = 1, limit = 3) {
const data = await client.getEntries({
content_type: 'posts',
skip: pageIndex * limit,
order: '-fields.publishDate',
limit,
})
if (data) {
return data
}
console.log('Something went wrong fetching data')
}
You may want to move the Contentful data fetching logic to the server as to not expose credentials and logic to the browser. This could be done using Next.js API routes.
// pages/api/posts.js
import client from '<path-to>/contentful-client' // Replace with appropriate path to file
export default async function handler(req, res) {
const { pageIndex = 1, limit = 3 } = req.query
const data = await client.getEntries({
content_type: 'posts',
skip: pageIndex * limit,
order: '-fields.publishDate',
limit,
})
res.json(data)
}
You could then refactor the code in your page to make a request against the newly created API route, passing the route URL as the key to useSWR.
import useSWR from 'swr'
const fetcher = (url) => fetch(url).then(res => res.json())
function Page({ index }) {
const { data } = useSWR(`/api/posts?pageIndex=${index}`, fetcher)
console.table(data)
return <div>nothing here, just testing</div>
}
export default Page

How to get getServerSideProps results in my IndexPage?

I don't think the getServerSideProps gets run, I'm just starting out and got no clue how to fix this, tried for a few hours but still getting undefined from the IndexPage console.log(props.data)
export default function IndexPage(props) {
console.log(props.data.copyright);
return (
<>
<div>{props.data.copyright}</div>
</>
)
}
export async function getServerSideProps() {
const res = await fetch(" https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY");
const data = await res.json();
return { props: { data } };
}
Edited: the code works perfectly on local machine and vercel deployment, but not on codesandbox.io where I originally started /headache
You have to use a React Hook, and then call the function inside of that. You can then store the response in a state instead
Try something like this:
import fetch from "isomorphic-unfetch";
import React, {useEffect} from "react"
const IndexPage = props => {
console.log(props.data);
if(!props.data){
return <div>Waiting for data...</div>
}
return <div>main page</div>;
};
export async function getServerSideProps() {
const { API_URL } = process.env;
console.log("inside fetch");
const res = await fetch(`${API_URL}/movies`);
const data = await res.json();
return { props: { data } };
}
export default IndexPage;
Otherwise you can use the
getStaticPropsThen ou are ensured, that the data is there, when the component fetches..

Easy Peasy state managment - How to fetch and pass data correctly?

I am using Easy Peasy State management for React. I would like to create multiple Axios call from one store location and import it in each page there where I need to show the correct data. I am trying to fetch a JSON placeholder data for example and use that inside a component to push it to the state using Hooks.
But I get the following error:
model.js:14 Uncaught (in promise) TypeError: actions.setTodos is not a function
at model.js:14
Can someone help me out? What am I doing wrong?
My code for the store (model.js):
import { thunk } from 'easy-peasy';
export default {
todos: [],
fetchTodos: thunk(async actions => {
const res = await fetch(
'https://jsonplaceholder.typicode.com/todos?_limit=10'
);
const todos = res.json();
actions.setTodos(todos);
}),
};
My Page component Contact:
import React, { useState, useEffect } from 'react';
import { useStoreActions } from 'easy-peasy';
import ReactHtmlParser from 'react-html-parser';
import { API_URL } from 'constants/import';
// import axios from 'axios';
const Contact = () => {
const [contactPage, setContactPage] = useState([]);
const { page_title, page_content, page_featured_image } = contactPage;
const fetchTodos = useStoreActions(actions => actions.fetchTodos);
useEffect(() => {
fetchTodos();
}, []);
return (
<section className="contact">
<div className="page">
<div className="row">
<div className="col-xs-12">
<h3 className="section__title">{page_title}</h3>
{ReactHtmlParser(page_content)}
{page_featured_image && (
<img src={API_URL + page_featured_image.path} />
)}
</div>
</div>
</div>
</section>
);
};
export default Contact;
You need to use action.
import { action, thunk } from "easy-peasy";
export default {
fetchTodos: thunk(async (actions, payload) => {
const res = await fetch(
"https://jsonplaceholder.typicode.com/todos?_limit=10"
);
const todos = res.json();
actions.setTodos(todos);
}),
todos: [],
setTodos: action((state, payload) => {
console.log("---->>> payload!")
state.todos = payload
}),
};
I usually use it like this, it works perfectly for me.

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