SSR with Helmet also render async meta and content? - reactjs

I'm trying to build an app where needs to get data before send props to <Helmet> but I don't know if it's possible because I don't see nothing like it in the docs.
And there's no possible to show this content in Helmet component. The content is always empty
The Helmet component is the HtmlPage component.
In the code below, we receive an SEO undefined error.
https://github.com/nfl/react-helmet/issues/409
<HtmlPage
{...this.props.client.info.SEO}
>
<ThemeProvider theme={this.state.theme}>
<div className='wrapper' id='wrapper'>
{loading && <Loading
client={this.state.client}
/>}
<div className="content" id='page-wrapper'>
<h1>Its ok for now ====</h1>
<p>
{JSON.stringify(this.props.client)}
</p>
<div>
{!!this.props.client.info &&
<p>{JSON.stringify(this.props.client.info.SEO)}</p>}
</div>
</div>
</div>
</ThemeProvider>
</HtmlPage>
The react-helmet-async don't work.
https://github.com/staylor/react-helmet-async

You need to implement a second renderPass to allow it to collect header elements. I tried react-tree-walker for this, but it didn't work. In the end I added a second renderPass using renderToStaticMarkup. E.g.
`
const stream = renderToNodeStream(<App preloadedState={preloadedState} />);
// extra render pass
renderPass(<App preloadedState={preloadedState} />);
`

Related

How to solve react hydration error in Nextjs

I have created small nextjs page using wordpress REST API, Now react-hydration-error error show this page.I am using react html parser npm. How do I solve this error. could you please solve this error.
my code:
import Image from 'next/image'
import React ,{Component}from 'react'
import Link from 'next/link';
import { BiCalendar } from "react-icons/bi";
import ReactHtmlParser from 'react-html-parser';
export default class Blog extends Component{
constructor(props){
super(props);
this.state={
data: props.bloglist,
isLoading: true,
dataLoaded: false,
};
}
render(){
if (!this.state.data) {
return null;
}
console.log(this.state.data)
return(
<>
<div className="container blog-section">
<div className='row'>
<h2>Latest Posts</h2>
</div>
<div className='row'>
{
this.state.data.map(((x,i) =>(
<div className='col-md-4 boxs text-center' key={i}>
<div className='bg-info'>
<img src={x.images.large} className='img-fluid'/>
<h3>{x.title.rendered} </h3>
<p className='shopping'><span><BiCalendar/> {x.date}</span> </p>
{/* <p dangerouslySetInnerHTML={{__html: x.excerpt.rendered}}></p><span><BiShoppingBag/> {x.slug}</span> */}
<p class='expert'>{ReactHtmlParser(x.excerpt.rendered)}</p>
<Link href={"/blog"+"/"+x.slug+"/"+x.id } passHref={true}><p className='readmore'><span>Readmore </span></p></Link>
</div>
</div>
)))
}
</div>
</div>
</>
)
}
}
My original issues:
paragraph coming this format <p>If you have heard that there are ways to make money while shopping in the UAE and would lik</p> from API, So I converted to html.
I had this error, in my case I had <p> tag nested inside another <p> tag,
I was using Typography (MUI v5) to render text, switching to <Box> from <Typography> fixed the error.
We use components to build the React-based websites, These components are made using HTML tags. It is very important not to nest the same HTML elements.
For Example:
function Logo() {
return (
<Link href="/">
<a>
<Image
src="/images/logo.svg"
width={100}
height={75}
/>
</a>
</Link>
);
}
export default Logo;
Above is the Logo Component which has already the <a></a> tag inside it.
In this example, you will get the React Hydration Error if the <a> tag is used inside another <a> tag.
<a href="#">
<Logo />
</a>
So do not include the same HTML tags, which are hidden inside the
components to avoid react hydration error.
In my case I am using NextJS and I had a dropdown with react-select, the default value was changing after a small calculation, that does not like to nextjs, this is my previous code:
<Select options={seasons}
onChange={() => setSeason(e.value)}
defaultValue={seasons.find((x) => x.value == season) ? seasons.find((x) => x.value == season) : seasons[0]}
/>
So, I changed that calculation to the useEffect and initialized the react-select dropdown only when that value was calculated,now this is my current code that works:
{defaultSeason && (<Select options={seasons}
onChange={() => setSeason(e.value)}
defaultValue={defaultSeason}
/>)}
So, basically check that the defaultValue or anything else does not change after the html is sent to the client part in NextJS.
Follow these: https://nextjs.org/docs/messages/react-hydration-error
Or try deleting <a> within <Link> maybe.
My first code was this:
const isUserLoggedIn = is_user_logged_in()
// is_user_logged_in() checks for cookie of user token and returns boolean
Got the error about hydration
Then changed code to this:
const [isUserLoggedIn, setIsUserLoggedIn] = useState(null)
useEffect(() => {
setIsUserLoggedIn(is_user_logged_in())
}, [])
Renders was like this:
{isUserLoggedIn ? (
<>
{/* After login */}
<Profile USER={USER}/>
</>
) : (
<>
{/* Before login */}
<SigninButtons/>
</>
)}
And error solved
You can also check this
https://nextjs.org/docs/messages/react-hydration-error
Just try restarting the server. npm run dev. It worked for me. I was using react-hot-toaster.
Also try to check if you have sth like this:
<p>
<div>
Hello
</div>
</p>
div cant be inside p tag

how to resolve "Prop `id` did not match. Server: "react-tabs-30" Client: "react-tabs-0" console issue?

i am trying tab in next in next.js, but every time i use it it show a console warning link this Prop `id` did not match. Server: "react-tabs-30" Client: "react-tabs-0", i know it isn't effect my app but it is so annoying. how to solve this waring
<Tabs>
<div className="tab-controler ml-sm-auto">
<TabList className="tab-lists list-inline d-flex flex-wrap nav mb-3" style={{ background: '#F8F8F8' }}>
<Tab className={`${CostCalculatorStyle.PEItem} tab-lists__item`}>Buy & Ship for me</Tab>
<Tab className={`${CostCalculatorStyle.PEItem} tab-lists__item`}>Ship for me</Tab>
</TabList>
</div>
<TabPanel key={"tabpanel_ship"}>
<div className="row">
<div className="col-lg-6">
<ShipForMeForm handleFormValue={handleFormValue} handleProductValue={handleProducts} handleRef={handleRef} />
</div>
<div className="col-lg-6 align-self-center">
<div className="costcalc-empty-thumb text-center">
<Image
src="/assets/topNavbarPages/costCalculator.svg"
alt="Cost Calculator"
width="469"
height="288"
/>
</div>
</div>
</div>
</TabPanel>
<TabPanel key={"tabpanel_buy_ship"}>
<div className="row">
<div className="col-lg-6">
<ShipForMeForm handleFormValue={handleFormValue} handleProductValue={handleProducts} handleRef={handleRef} />
</div>
<div className="col-lg-6 align-self-center">
<div className="costcalc-empty-thumb text-center">
<Image
src="/assets/topNavbarPages/costCalculator.svg"
alt="Cost Calculator"
width="469"
height="288"
/>
</div>
</div>
</div>
</TabPanel>
</Tabs>
as you can see i use react-tabs for tab but i also work on react js where i use the same code but it didn't show this console warning. so my question is why it is happing? and how i can solve it ?
In next js i fixed it like that
import dynamic from 'next/dynamic'
const Tabs = dynamic(import('react-tabs').then(mod => mod.Tabs), { ssr: false }) // disable ssr
import { Tab, TabList, TabPanel } from 'react-tabs'
it work for me
The best solution I know of is just to set the id yourself in the <Tabs> component. Ex: <Tabs id={1}>
See https://github.com/chakra-ui/chakra-ui/issues/4328#issuecomment-890525420 for more details and examples.
NextJs generating code in server side as you know.
This error means that something on the server is different from the Client. This can happen if the client does a re-render.
For example.
export default function Test(props) {
return (
<>
<span>{props.name}</span>
</>
);
}
I have this simple Test component.And I send name (1) prop from another component to this Test component. And if I change this name (to 2) in client using redux (for example I have another name in my redux store) after page generated I get this error.
props did not match server "1" client "2"
To solve this error I need to just not change this name with redux after page generated in server. The data can be change only with user manipulations after page rendered in server.
Same thing happened to me when I use Tabs from react-bootstrap. Koushik Saha's answer can be apply for that also but with a small change. Need to put react-bootstrap instead react-tabs
const Tabs = dynamic(import('react-bootstrap').then(mod => mod.Tabs), { ssr: false })
In case you miss it
If you are using Nextjs + Material-ui, there are actually custom codes that you can/need to include in your _document.js and _app.js to remove the server-side injected CSS so the CSS is recreated when page loads.
As codes changes with mui's and nextjs' version, i will refer you to the repository directly
https://github.com/mui-org/material-ui/tree/master/examples/nextjs/pages
As per the documentation in the react-tabs repo/npmjs.org page (https://www.npmjs.com/package/react-tabs):
import { resetIdCounter } from 'react-tabs';
resetIdCounter();
ReactDOMServer.renderToString(...);
I was having the same issue and called the resetIdCounter function inside my parent component to the tabs structure and cleared up the error.
Not sure if maybe there is a better place to use this function, like maybe in a useEffect hook or something, but I'm going with this for now.

Reactjs component - one vs many

I'm new to react and I'm trying to figure out the best way to make a component that can handle different scenarios. I'm not sure if the best practice would be to make multiple components or one component to handle it all.
Imagine a frontpage were you have 3 different entrances like recent products, blogpost or Instagram pictured. Each entrance use a component called featured and inside that component I should render either products, blogpost or Instagram pictures. Everything for the layout is the same, its just the items in the grid that needs to change. What would be the best way to solve this? one component with 3 different sub-components or 3 components with one for each type.
I know how to make 3 different components, but I'm not sure how to make one component to handle subcomponents.
This could be the component and the "grid-item--product" could also be a "grid-item--blogpost or "grid-item--Instagram" - "grid" could also be a "two-col" or "three-col".
<div className="featured">
<div className="featured--content">
<div className="grid four-col">
<grid-item--product />
</div>
</div>
</div>
and this could be where I would call the component and hopefully be able to handle which component should be rendered inside and what the grid should be for this feature.
<div className="frontpage-route">
<h2>Frontpage Route</h2>
<Featured />
</div>
Can you help me? I would love an example if possible.
Thanks.
It sounds like what you want is the children prop. You can add the children prop to Featured and just pass the correct children to it. See an example here:
const Featured = ({ children, numColumns = "one" }) => (
<div className="featured">
<div className="featured--content">
<div className={`grid ${numColumns}-col`}>
{children}
</div>
</div>
</div>
)
const App = () => (
<div className="frontpage-route">
<h1>Frontpage Route</h1>
<h2>Products</h2>
<Featured numColumns="two">
<grid-item--product />
<grid-item--product />
</Featured>
<h2>Blogs</h2>
<Featured numColumns="three">
<grid-item--blog />
<grid-item--blog />
</Featured>
<h2>Instagram</h2>
<Featured>
<grid-item--instagram />
<grid-item--instagram />
</Featured>
</div>
)
You can use consitional rendering and three boolean variables to display components.
e.g:
<div className="featured">
<div className="featured--content">
<div className="grid four-col">
{product && <grid-item--product />} //if product var is true this component renders
{blogpost && <grid-item--blogpost />} //if blogpost var is true this component renders
{instagram && <grid-item--instagram />} //if instagram var is true this component renders
</div>
</div>
</div>

React 16 warning "warning.js:36 Warning: Did not expect server HTML to contain a <div> in <div>."

I'm using the React 16 beta (react-fiber) with server side rendering
What I am to understand this to mean?
warning.js:36 Warning: Did not expect server HTML to contain a <div> in <div>.
Just change express response from
<body>
<div id="root">
${markup}
</div>
</body>
to
<body>
<div id="root">${markup}</div>
</body>
Remove space between tags
Looking for that error in the react code it seems that this happens when the SSR html can't be rehydrated.
https://github.com/facebook/react/blob/7a60a8092144e8ab2c85c6906dd4a7a5815cff1f/src/renderers/dom/fiber/ReactDOMFiberComponent.js#L1022
So you are somehow initially rendering a different tree on the client vs the server.
I faced the same warning while using Modal in Next.js. I was working to create a popup on the main page.
I found a solution. If the modal show state comes true first, it produces this warning. So I made it first undefined then I set it true after the page rendered . The code is below.
const [modalShow, setModalShow] = React.useState();
useEffect(() => {
if ( modalShow === undefined ) {
setModalShow(true)
}
}, [modalShow])
I had this issue, I solved it where I changed this:
<div>
<Header />
{children}
</div>
to this:
<div>
<Header />
<div>{children}</div>
</div>
My issue was react-loadable: The code used LoadableComponent for client only which wrapped each of my React-Component in client.
The cause was hard to find because Client and Server rendered the same HTML.
My Solution:
upgrade to node 16.x
remove react-loadable
load all components using import

Can only set one of `children` or `props.dangerouslySetInnerHTML`

I'm trying to set the inner HTML of an alert div, but receiving the error message : Can only set one of 'children' or props.dangerouslySetInnerHTML'.
Why does this happen ?
function alertContent(alert) { return {__html: alert.text} }
const Alerts = ({ alerts=[{level: 'warning', text:'<p>Warning message!</p>'}], onDismiss }) => (
<div className="alerts">
{alerts.map(alert =>
<Alert
bsStyle={alert.level}
key={alert.id}
onDismiss={onDismiss}
dangerouslySetInnerHTML={alertContent(alert)}
></Alert>
)}
</div>
)
I had this error message in a react application.
My issue was I had code as below
<p dangerouslySetInnerHTML={{ __html:stringContainingHtml}}> </p>
My issue was the space in the <p> </p> tags - since html gets injected inside these tags the space was causing an issue as it wasn't empty.
Hope this might help some people.
This happens because dangerouslySetInnerHTML can only be applied to one element. In your case, <Alert/> is a complex element made up of multiple children. That being said, the BS Alert component does accept HTML:
<Alert bsStyle="warning">
<strong>Holy guacamole!</strong> Best check yo self, you're not looking too good.
</Alert>
or
<Alert bsStyle="warning">
<span dangerouslySetInnerHTML={alertContent(alert)} />
</Alert>
Solution, You have to make a separate component to render element in which you are using dangerously set.....
For Example:
const RenderHTML = (props) => (<span dangerouslySetInnerHTML={{__html:props.HTML}}></span>)
YourData.map((d,i) => {
return <RenderHTML HTML={d.YOUR_HTML} />
})
you have to close the html tag short hand if there aren't inner HTML
<Alert dang...={} />
instead <Alert></Alert>
I have solved this issue myself.
When you are recursively rendering a component, you must separate out the part of the component where dangerouslySetInnerHTML is being used into another component and then use that component in the one you are recursively rendering.

Resources