NextJs GetServerSideProps after update how can i call? - javascript

Below I am pulling all the data from the database. But let's say I deleted one piece of data. How can I retrieve the renewed data? How can I run it again?
export async function getServerSideProps() {
const res = await fetch(`http://localhost:8000/api/getAllShipmentTypes`);
const shipmentTypes = await res.json();
return {
props: { shipmentTypes } // will be passed to the page component as props
};
}

But let's say I deleted one piece of data. How can I retrieve the renewed data?
I think you will need to define what is the trigger for the deletion, I can think of these two.
Another action user performs on a page.
Some other system modifying the database that this client application shows.
For #1, To the action, say a button click you can use a router object to set the same route again which will run getServerSideProps again
When you request this page on client-side page transitions through next/link or next/router, Next.js sends an API request to the server, which runs getServerSideProps
For #2 - this would be handled by giving the user an option to refetch the data from the server again using a link or router component

You can do something like:
import { useRouter } from 'next/router';
function SomePage(props) {
const router = useRouter();
// Call this function whenever you want to
// refresh props!
const refreshData = () => {
router.replace(router.asPath);
}
}

Related

NextJS: Do I need to use getInitialProps with next-redux-wrapper to share state to all pages?

I'm using next-redux-wrapper and dispatching actions from getServerSideProps from individual pages. But I realized that I can't access the populated store state from another page. If I try to, in either client-side or server-side, the state returns empty in the other pages.
So, I heard that using getInitialProps is required to share state among all pages. Since I'm getting confused with all these I want to have some doubts cleared. I want to know:
When is it necessary, if at all, to use getInitialProps in the _app.js file when using redux with next-redux-wrapper? I heard that need to use getInitialProps inside _app.js in order to make the state accessible to every pages. But it's not working for me. Maybe due to wrong implementation!
If I use getInitialProps in _app.js then, is it not required to use getServerSideProps or getStaticProps in individual pages?
After populating state with getServerSideProps, can I share the state to every page without using getInitialProps in _app.js or if nneded can I pass the fetched state to getInitialProps in _app.js?
Yes, You have to use getIntitprops in the APP component to provide store in all pages in this case all page will run on a server which huge downfall, if you have lots of static pages,
or you can use this code on each page according to your needs but your dispatch will change server-side state only!!!, which means you can access them on the client-side.
export const getServerSideProps = wrapper.getServerSideProps(async ({ store, query }) => {
try {
const { id } = query
const res = await api.get('/abc', { params: { id } })
await store.dispatch(action)
return {
props: {
id,
data: res.data,
isServer: typeof window === 'undefined',
}
}
} catch (error) {
return {
props: {
errorCode: 409,
message: "Data Unavailable"
}
}
}
})
In the end, I ditched both options because it provides a bad user experience.
My recommendation is to use getInitProps and check if the page is rendering on the server then call API and save props in client-side, otherwise call API in the client a and save it.

NextJS initial state is not updating when routing to same page with different params

This project is using NextJS
I have a page which URL looks like this
localhost:3000/first/second
I call getInitialProps on that page. Data is passed from getInitialProps to the component as it should be and I am setting initial state with that data like this
const Index = ({ data }) => {
const [state, setState] = useState(data.results)
}
Now when I send the user to
localhost:3000/first/third
getInitialprops is called as it should be. data, that is a parameter of component, is always populated with the latest results from getInitialProps but state isn't. It is populated with previous data that was in it. It is not resetting when I am doing client-side routing. Only when I hard refresh the page.
As suggested on NextJS GitHub I tired adding data.key = data.id, in ```getInitialProps``,` that is always a different number to force state update but it is not working.
Any info will be useful.
Thank you for your time :)
When using NextJS, getInitialProps is called before the page renders only for the first time. On subsequent page renders (client side routing), NextJS executes it on the client, but this means that data is not available before page render.
From the docs:
For the initial page load, getInitialProps will run on the server only. getInitialProps will then run on the client when navigating to a different route via the next/link component or by using next/router.
You would require a useEffect to sync state:
const Index = ({ data }) => {
const [state, setState] = useState(data.results);
useEffect(() => {
setState(data.results);
}, [data]);
}

Vue-test-utils doesn't wait for the response from the API request

I've been really struggling to do something very simple. I have to write some tests for a Vue application.
The scenario I want to test is the following:
The user fills in a form
The user submits the form
The values from the form are sent to the backend in one object
The server responds with an object containing the fields of the object it has received in the request (plus some new fields).
The Vue app stores the result in the Vuex store
I want my test to check if, after the form has been validated, the request is made and the returned values are properly stored in the store.
This is super basic, but for some reason I can't get the test to work.
I have a globally registered component that makes axios accessible by using this.api.
So in my test, I have the following (the file is simplified for this post):
...
import axios from 'axios';
import AxiosMockAdapter from 'axios-mock-adapter';
import flushPromises from 'flush-promises';
// This is the axios setup used in the components
import api from '../../src/mixins/api';
// Components
import MyComponent from '../component.vue';
describe('MyComponent', () => {
// Set up the local vue
...
const wrapper = mount(MyComponent, {
localVue,
...
});
beforeEach(() => {
const instance = axios.create({
baseURL: 'some/url/',
});
wrapper.vm.api = new AxiosMockAdapter(instance);
wrapper.vm.api.onPost('url/').replyOnce(201, { data: { foo: 'bar' } });
});
it('should retrieve the data', async () => {
wrapper.find('#submit').trigger('click');
await flushPromises();
expect(wrapper.vm.$store.state.foo !== undefined).toBe(true);
});
});
But the test isn't successful. I think the request is made properly, but by the time the test reaches its end the response hasn't be received yet. And this is despite using flushPromises(). I also tried to use setTimeout but with no success neither.
I'm new to unit testing (especially on front end apps) and I have no idea what else to try. Nothng works... It's very frustrating because what I'm tryng to do is pretty straight forward and basic.
Anyone has an idea what to do ?

useQuery after server-side rendering

I'm using next.js and apollo with react hooks.
For one page, I am server-side rendering the first X "posts" like so:
// pages/topic.js
const Page = ({ posts }) => <TopicPage posts={posts} />;
Page.getInitialProps = async (context) => {
const { apolloClient } = context;
const posts = await apolloClient.query(whatever);
return { posts };
};
export default Page;
And then in the component I want to use the useQuery hook:
// components/TopicPage.js
import { useQuery } from '#apollo/react-hooks';
export default ({ posts }) => {
const { loading, error, data, fetchMore } = useQuery(whatever);
// go on to render posts and/or data, and i have a button that does fetchMore
};
Note that the useQuery here executes essentially the same query as the one I did server-side to get posts for the topic.
The problem here is that in the component, I already have the first batch of posts passed in from the server, so I don't actually want to fetch that first batch of posts again, but I do still want to support the functionality of a user clicking a button to load more posts.
I considered the option of calling useQuery here so that it starts at the second "page" of posts with its query, but I don't actually want that. I want the topic page to be fully loaded with the posts that I want (i.e. the posts that come from the server) as soon as the page loads.
Is it possible to make useQuery work in this situation? Or do I need to eschew it for some custom logic around manual query calls to the apollo client (from useApolloClient)?
Turns out this was just a misunderstanding on my part of how server side rendering with nextjs works. It does a full render of the React tree before sending the resulting html to the client. Thus, there is no need to do the "first" useQuery call in getInitialProps or anything of the sort. It can just be used in the component alone and everything will work fine as long as getDataFromTree is being utilized properly in the server side configuration.

Persist some data through routechange in next.js

So basicly we have an initial fetch in our custom pages/_app.jsx that first fetches sitesettings & navigation for header/footer. This data I would like to be only fetched once however it gets fetched every routechange clientside. Is there anyway to persist some data after the initial fetch in the app container?
Here's my code:
import React from 'react'
import App, { Container } from 'next/app'
import Header from '../components/Header';
import Footer from '../components/Footer';
class MyApp extends App {
static async getInitialProps({ Component, router, ctx }) {
let pageProps = {}
const res = await fetch(`http://localhost:3000/navigation`)
const nav = await res.json();
const ss = await fetch(`http://localhost:3000/site-settings`);
const settings = await ss.json();
var culture = "en-us";
var root = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
if (pageProps && pageProps.pageContext) {
culture = pageProps.pageContext.culture || "en-us";
root = nav.message.find(nav => !nav.parentPage && nav.culture === culture);
}
}
return {
pageProps,
navigation: nav.message,
settings,
culture,
root
}
}
And the issue is that the getInitialProps of my _app.jsx is being run at every route making unecessary requests to fetch data that client already have.
There are three separate issues here: first, performing the fetch in _app will guarantee execution for every page, since it is used to initialize each page. That is not what you want. Instead this should happen in the appropriate page.
Second, this shouldn't happen in getInitialProps as that delays the loading of the page. If that is intended, go ahead and do it - but it would be better practice to render the page ASAP, and fill in the gaps later, rather than showing a blank screen.
Third, and most important, you need to load the information you need and manage it in some sort of application state that is shared between all pages. That can be done in redux, React Context, or your own solution for storing the received information if the other solutions feel like overkill for your project. That way you can check if you have it before fetching, and only fetching once.

Categories