Hybrid render with Next.js? - next.js

I'm new to Next.js and I'm using it to perform server side rendering on the landing page.
The landing page has: 1 generic component that's the same to every user and 1 component that is specific for each user.
Is it possible to perform server side rendering on the generic component, and client side rendering on the specific one?
Thank you.

Yes, you can do client-rendering for any component in your hierarchy. Client rendering usually means that when the component first renders, it fires off some asynchronous request for data (from an API, etc).
In your SSR page, just have your user-specific component not render anything on the initial render (except maybe some loading UI). Then include a useEffect hook that triggers the API call and sets state (local or global state as appropriate) which will trigger your component to re-render with the user-specific data.
During SSR, only the loading state will render. As soon as the component is mounted, the useEffect will trigger and the user-specific data will load and the component will re-render.
Overly simplistic example:
const UserGreeting = () => {
const [name, setName] = setState();
useEffect(() => {
getUserNameAsync().then((data) => {
setName(data.name);
})
}, [setName])
if (!name) {
return <div>...</div>
}
return (
<div>Welcome, {name}</div>
)
}

To make a page both dynamic and static at the same time is possible.
the solution for dynamic: you have to use react useState then useEffect to send the request after unloading fishing on the client side
but first must use next.js api getStaticProps() make the page static user's first visit

Related

How to entirely disable server-side rendering in next.js v13?

The documentation says that I can disable server-side rendering by adding 'use client' to the top of files that need to be rendered only client-side.
However, in practice, I've added this header to every file in the project, and I see that both Layout and Page are being rendered server-side.
I can confirm this with a simple page:
'use client';
export default () => {
console.log('SERVER RENDER (page)');
return (
<div>test</div>
);
};
I would expect next dev to not output "SERVER RENDER (page)", but it does.
You don't need to disable server-side rendering (SSR), as it's not enabled by default in Next.js.
It pre-renders every page unless instructed otherwise, using either Static Generation or SSR.
Static Generation. The HTML generated at build time and will be reused at every request.
SSR. The HTML is generated on each request.
Next.js uses Static Generation whenever possible.
In your example, SSR doesn't happen. You're seeing the SERVER RENDER (page) message in terminal because you run it in dev (next dev) mode. In dev mode there is no build done, so the pages are generated on the go. You won't see this message in production mode. See this for more details.
Using use client; directive doesn't change the above, it just tells Next.js that a component is a Client Component, which will still be pre-rendered.
It looks like even if a component is marked 'use client', it will still be pre-rendered.
Client Components enable you to add client-side interactivity to your application. In Next.js, they are prerendered on the server and hydrated on the client. You can think of Client Components as how Next.js 12 and previous versions worked (i.e. the pages/ directory).
https://beta.nextjs.org/docs/rendering/server-and-client-components#client-components
#Nikolai pointed this out correctly, but did not answer how to disable SSR.
However, now that we know that Next 13 behaves the same as 12, we can also apply the same hydration workaround that was used in previous versions.
The TLDR is that you want to wrap your layout in a component that conditionally renders the element based on whether it detects the browser environment, e.g.
const Dynamic = ({ children }: { children: React.ReactNode }) => {
const [hasMounted, setHasMounted] = useState(false);
useEffect(() => {
setHasMounted(true);
}, []);
if (!hasMounted) {
return null;
}
return <>{children}</>;
};
export default ({ children }: { children: React.ReactNode }) => {
return (
<html lang="en">
<head />
<body>
<Dynamic>{children}</Dynamic>
</body>
</html>
);
};
Obviously, make sure you know what you are doing. This is generally not desired behavior, though there are exceptions.

Next.js advanced client-side routing

In a Next.js app (full-featured, not next export) that uses React Context for state management and the file-system based router, how can you implement advanced routing?
I want to have preconditions for certain pages, so for instance if you try to load /foo but the Context doesn't have a given property set correctly, it'll route you to /bar.
The actual logic is complex and varies by page, so I'm looking for an approach that's easy to maintain.
Note that these preconditions are not authorization-related, so they do not need to be enforced server-side. It's more like "you need to fill out this form before you can go here."
The use of Context imposes some constraints:
Context must be accessed in a React component or in a custom Hook
Using a custom server for routing is not an option, as that would lose the Context - it has to use client-side routing
The current Context has to be checked (I tried decorating useRouter, but if the Context was changed right before router.push, the custom Hook saw the old values)
Update: It's also good to avoid a flash when the page loads before rerouting happens, so a side goal is to return a loading indicator component in that case.
I believe you can create a HOC and wrapped every pages with you HOC that takes arguments e.g. { redirects: '/foo' }
// pages/bar.tsx
const Page = () => {...}
export default RouteHOC({ redirects: '/foo' })(Page)
the HOC file will be something like this
// hoc/RouteHOC.tsx
const RouteHOC = ({ redirects }) => (WrappedComponent) => {
// you can do your logic here with the context.. even filling up a form here
// too also can.. (like returning a modal first before the real Component).
// useEffect work here too..
const { replace } = useRouter()
// then after you want to replace the url with other page
replace(redirects)
return WrappedComponent
}
This is pretty okay to be maintainable I think. You just create all the logic in HOC and when you want to update the logic - you just have to edit it in 1 file.
Well this is one option I can think of when reading your question - sorry if I misunderstood it in any way. There will always be a better way out there as we all know we can improve and adapt to new situation every seconds :D. Cheers 🥂!!
You can do this.
const Component = () => {
const example = useExample()
return <div id='routes'>
<a href='/example1'>Example 1</a>
{example.whatever && <a href='/example2'>Example 1</a>}
</div>
}

redux causing component re-rendering

I have a component which is connected to global store and getting some data from the global store. from some portion of this data is sent to another component via props and inside that component i have generated required jsx based on data. Also inside the child component mapdispatchtoprops is also used and it is also connected to global store as well.
The problem case scenario is child component re-renders depends upon the global store data.
The key for global store is like -
foods : {
'list' : '',
's' : '',
fetching : 0,
slist : '',
category : '',
cproducts : ''
}
I guess what happening is the child component is re-rendered 7 times because the number of keys inside global store for foods is 7. if anyone is interested he/she can share his/her views
Components have a render method which returns the JSX markup that it renders to the DOM. For change detection, React use a local state, which is only local to a component, when the state changes the component and its children are re-rendered to update the UI of the changed state.
A quote from the React documentation:
These components must not retain internal state, do not have backing instances, and do not have the component lifecycle methods. They are pure functional transforms of their input, with zero boilerplate. However, you may still specify .propTypes and .defaultProps by setting them as properties on the function, just as you would set them on an ES6 class.
PURE COMPONENT is one of the most significant ways to optimize React applications. The usage of Pure Component gives a considerable increase in performance because it reduces the number of render operation in the application.
So change your app to be like this
import React, {PureComponent} from 'react';
class Sample extends PureComponent {
render() {
return (
<div>your structure here</div>
)
}
}
export default Sample;
Please read more on react PureComponent. here

redux and listening to scroll events

Building a performance sensitive Redux app that needs to listen to scroll/mouse events throughout a user session.
Plain english implementation would be:
"When component A is in the user's viewport, dispatch FOO action"
From my understanding, the function calculateViewPort + the comparison checking would need to be conducted in the store on every scroll event.
This seems excessive and slow (haven't tested it yet).
Is there another implementation or approach that I have not yet considered?
I was thinking about using something like RxJS for Redux, but want to consider the tradeoff between bringing in a new library for performance and solving it with my existing toolkit.
If there's a saga approach, I'm more open to that too.
There is a InfiniteScroll component. You can refer this and implement in your way or you can use as it is.
Note: this component is not using the redux-saga.
It's better to go with redux-saga as you would take only the response which comes from the latest api call (last mouse scroll) with takeLatest effect.
React Visibility Sensor might be a good choice here. You can wrap the components in VisibilitySensor component and dispatch an action whenever it is on window viewport.
import React from 'react'
import { connect } from 'react-redux'
import VisibilitySensor from 'react-visibility-sensor'
import CUSTOM_ACTION from 'your-actions'
const CustomComponent = (noticeMe, ...children) => {
const handleChange = (isVisible) => { if (isVisible) { noticeMe(); } }
return <VisibilitySensor>{children}</VisibilitySensor>
}
export connect({}, {
noticeMe: () => dispatch(CUSTOM_ACTION)
})(CustomComponent)

How to make react application SEO friendly

If I want to use Google analytics and at the same time make my site SEO friendly in React, what is the best way?
At the moment I use react-router and a flux pattern where I change the route and then in componentDidMount I fire an action that loads my data through ajax and then updates the store which emits the change and finally I re-render the components that are affected. During the ajax loading I dispatch an event so that my store knows ajax is loading and render a spinner in my component.
I have noticed that when I send my tracking data to Google the ajax has not finished loading and I only send the new page URL not the title or any other data which I load through ajax (I guess this is bad from an SEO perspective and it's definitely bad for my GA data).
This is my GA setup (I use react-ga):
Router.run(routes, Router.HistoryLocation, function(Handler, state) {
ga.pageview(state.pathname);
React.render(<Handler />, document.body);
});
Typical component setup (which allows me to render the correct data based on the URL):
componentDidMount: function() {
ItemStore.addChangeListener(this._onChange);
if(itemSlug) {
ItemActions.loadItemBySlug(this.props.slug);
}
}
I want to be able to have a single point of GA tracking if that is possible. I also want the SEO handling to be correct for the page:
Page title
OG data
H1
etc ...
What is the best approach to solve this?
Should I use the willTransitionTo option in react-router for this? (is it possible to use a loading spinner if I opt for this solution?)
statics: {
willTransitionTo: function (transition, params, query, callback) {
// LOAD AJAX HERE ?
callback();
}
}
How would I go about the willTransistionTo solution in a proper way, can't seem to find any good examples that relate?
Should I add more code, or is it clear what I'm trying to achieve?
Trigger the ga.pageview after the store gets the new data and renders.
The appropriate way to handle SEO in react is to render at the server side isomorphically with React.renderToString, so that any search engine will see the page in its complete state, rather than just Google's spider and only on those occasions when you manually call it.
This was one of the original design criteria of React.

Resources