React framework Remix Prop className did not match [duplicate] - reactjs

This question already has answers here:
Warning: Prop `className` did not match. when using styled components with semantic-ui-react
(17 answers)
Closed last month.
I'm using Styled-component with remix
and I got "Prop className did not match" this error but I don't know How to solve this error
I searched about this error but There was only answer about next js
help me
console error
Warning: Prop `className` did not match. Server: "sc-gswNZR iqcxXn" Client: "sc-bcXHqe djVGJv"
this is code I just starting to develope my project with remix and styled-component
I think it because of server side rendering problem
however I couldn't solve this error
code
import { Link } from "#remix-run/react";
import styled from "styled-components"
export const Container = styled.div`
text-align: center;
&& img{
width: 100px;
}
`
export default function Index() {
return (
<Container>
<Link to="remixtamain">
<img src={"https://ifh.cc/g/jd5MrN.png"}/>
</Link>
</Container>
);
}

Awww I found the way in an official document
https://github.com/remix-run/examples
this is the example SSR styleing
First I edit entry.server.tsx like this
import type { EntryContext } from "#remix-run/node";
import { RemixServer } from "#remix-run/react";
import { renderToString } from "react-dom/server";
import { ServerStyleSheet } from "styled-components";
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const sheet = new ServerStyleSheet();
let markup = renderToString(
sheet.collectStyles(
<RemixServer context={remixContext} url={request.url} />
)
);
const styles = sheet.getStyleTags();
markup = markup.replace("__STYLES__", styles);
responseHeaders.set("Content-Type", "text/html");
return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
I added this {typeof document === "undefined" ? "STYLES" : null} in root tsx
in Head tag
import type { MetaFunction } from "#remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "#remix-run/react";
export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
});
export default function App() {
return (
<html lang="en">
<head>
<Meta />
<Links />
{typeof document === "undefined" ? "__STYLES__" : null}
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
and its work!

Related

How to use mantine UI with next 13

I was trying to use mantine UI with NextJS 13 using the app directory,
I have to wrap everything in the MantineProvider component but I don't know where to put it.
I tried this
layout.js
/* eslint-disable #next/next/no-head-element */
import { MantineProvider } from '#mantine/core';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<MantineProvider
withGlobalStyles
withNormalizeCSS
theme={{
/** Put your mantine theme override here */
colorScheme: 'dark',
}}>
<html>
<head></head>
<body>{children}</body>
</html>
</MantineProvider>
);
}
and it didn't work
so, is there any solution??
So I've been interested in solving this problem too.
Step 1 is moving third-party providers to a "client-only" component.
See here
The next step is to follow this thread on mantine's github, while they work out compatibility issues with emotion & next13
Lastly, this seems to be the only official implementation example on Mantine's github using Mantine with the new Next.js app directory.
Here's how they approached it:
/app/emotion.tsx
"use client";
import { CacheProvider } from "#emotion/react";
import { useEmotionCache, MantineProvider } from "#mantine/core";
import { useServerInsertedHTML } from "next/navigation";
export default function RootStyleRegistry({
children
}: {
children: React.ReactNode
}) {
const cache = useEmotionCache();
cache.compat = true;
useServerInsertedHTML(() => (
<style
data-emotion={
`${cache.key} ${Object.keys(cache.inserted).join(" ")}`
}
dangerouslySetInnerHTML={{
__html: Object.values(cache.inserted).join(" "),
}}
/>
));
return (
<CacheProvider value={cache}>
<MantineProvider withGlobalStyles withNormalizeCSS>
{children}
</MantineProvider>
</CacheProvider>
)
}
/app/layout.tsx
import RootStyleRegistry from './emotion';
export default function RootLayout({ children }) {
return (
<html lang="en-US">
<head />
<body>
<RootStyleRegistry>{children}</RootStyleRegistry>
</body>
</html>
);
}
Hope this helps. Let me know if you get it working

How to use query param as a variable in groq sanity query inside getServerSideprops in next js?

I'm trying to implement search fuctionality in my blog project but facing problem in using variable in groq query(sanity) inside getServersideprops.
Here is my code
import React from 'react'
import { useRouter } from 'next/router'
import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import Banner from '../../components/Banner'
import Header from '../../components/Header'
import { sanityClient,urlFor } from '../../sanity'
import { Post } from '../../typings'
import PostCard from '../../components/Post'
import Footer from '../../components/Footer'
import BottomNav from '../../components/BottomNav'
interface Props{
posts:[Post];
}
export default function Search({ posts}:Props) {
return (
<>
<div className='max-w-6xl mx-auto container-fix md:mb-1 '>
<Head>
<title>Const - Read for free</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Header/>
<Banner/>
<PostCard posts={posts} />
<Footer/>
</div>
<BottomNav />
</>
)
}
export const getServerSideProps = async(context:any)=>{
const search = context.query.url;
const query = `
*[_type=="post" && title == $search]{
_id,
title,
author -> {
name,
image,
},
_createdAt,
description,
mainImage,
category,
slug
}`;
const posts = await sanityClient.fetch(query);
return {
props:{
posts
}
}
}
this is the error im getting
**Server Error
ClientError: param $search referenced, but not provided
**
but when the variable is repalced with actual string then I'm geeting results succesfully.
groq query doesnot pick the variable directly from declaration .need to pass the variable in sanityclient.fetch() alongside the query.
const posts = await sanityClient.fetch(query,{search:search});

document is not defined when creating new portal in Nextjs

in my project I want to separate section like menu in header tag, content in main tag and contact in footer tag _document.js file, for this I created a new portal but I get an error document is not defined in my Header.js file.
I trying to create new portal in nextjs like this:
import React, { Fragment } from "react";
import ReactDOM from "react-dom";
import NavigationBar from "./NavigationBar";
import classes from "./header.module.css";
const Header = (props) => {
return (
<Fragment>
{ReactDOM.createPortal(
<NavigationBar>{props.children}</NavigationBar>,
document.getElementById("header")
)}
</Fragment>
);
};
export default Header;
I created _document.js:
import Document, { Html, Head, Main, NextScript } from "next/document";
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
return (
<Html lang="en" dir="ltr">
<Head />
<body>
<header id="header"></header>
<Main />
<footer id="_footer"></footer>
<div id="_modal"></div>
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
The error is thrown because document is only available inside the browser and not on the server. Next js executes this code on the server side and that's why the error is thrown.
You can wrap our code inside an if statement. If you check on the console the type of window it returns object. The following code illustrates this:
if (typeof window === 'object') {
// Check if document is finally loaded
}
Use React portal maker:
import React from "react";
import reactDom from "react-dom";
const Header = (props) => {
const content = <NavigationBar>{props.children}</NavigationBar>;
if (typeof window === "object") {
return reactDom.createPortal(content, document.getElementById("__header"));
}
return null;
};
export default Header ;

Next.js 9+ FOUC (Flash or Unstyled Content) with Styled Components

Have spent a couple days on this issue sourcing solutions and ideas from most of SA and Reddit however to no avail..
Upon load both in production and local every load presents the whole html without any styling before then being injected into DOM..
Currently this is my projects key files:
_document.js
import { ServerStyleSheet } from "styled-components";
import Document, { Main, NextScript } from "next/document";
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
render() {
return (
<html lang="en">
<Head>
<title>namesjames</title>
<link rel="icon" href="/favicon.ico" />
<script src="/static/chrome-fix.js" />
<link href="/above-the-fold.css" />
</Head>
<body>
<script src="/noflash.js" />
<Main />
<NextScript />
<script> </script>
</body>
</html>
);
}
}
_app.js
/* eslint-disable class-methods-use-this */
import App from "next/app";
import React from "react";
import { ThemeProvider } from "styled-components";
import { ParallaxProvider } from 'react-scroll-parallax';
import Header from "../components/Header";
import theme from "../theme";
import GlobalStyles from "../GlobalStyles";
import DarkModeToggle from '../components/toggle/toggleMode';
import Footer from '../components/Footer'
import LazyLoad from 'react-lazy-load';
import Router from 'next/router';
import styled from 'styled-components'
// import '../style.css'
const Loaded = styled.div`
opacity: ${(props) => props.loaded ? "1" : "0"};
`
export default class MyApp extends App {
state = { isLoading: false, loaded: false }
componentDidMount() {
// Logging to prove _app.js only mounts once,
// but initializing router events here will also accomplishes
// goal of setting state on route change
console.log('MOUNT');
this.setState({loaded: true})
Router.events.on('routeChangeStart', () => {
this.setState({ isLoading: true });
console.log('loading is true, routechangeStart')
});
Router.events.on('routeChangeComplete', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeComplete')
});
Router.events.on('routeChangeError', () => {
this.setState({ isLoading: false });
console.log('loading is false, routeChangeError')
});
}
render(): JSX.Element {
const { isLoading } = this.state;
const { Component, pageProps, router, loaded } = this.props;
return (
<Loaded loaded={this.state.loaded}>
<ThemeProvider theme={theme}>
<GlobalStyles />
<ParallaxProvider>
<Header />
{isLoading && 'STRING OR LOADING COMPONENT HERE...'}
<Component {...pageProps} key={router.route} />
<LazyLoad offsetVertical={500}>
<Footer />
</LazyLoad>
</ParallaxProvider>
<DarkModeToggle />
</ThemeProvider>
</Loaded>
);
}
}
index.js
import { color } from "styled-system";
import { OffWhite } from "../util/tokens";
import Hero from "../components/Hero";
import Banner from '../components/Banner'
import TitleText from '../components/TitleText'
import HomeTitleCopyScene from '../components/HomeTitleCopyScene'
import TwoCards from '../components/TwoCards'
import LazyLoad from 'react-lazy-load';
function Home(): JSX.Element {
return (
<div className="container">
<Banner />
<HomeTitleCopyScene />
<LazyLoad offsetVertical={1000}>
<TwoCards />
</LazyLoad>
</div>
);
}
export default Home;
As some might see I have tried multiple implementations and am just a bit confused as to what it could be at this stage..
Any help appreciated and I can provide more information upon request.. Many thanks
I found two solutions which helped -->
Was to hard style opacity:0 into the JSX and then upon styling injecting into DOM applying opacity: 1 !important onto any of the components displayed..
<section className="cards-block" style={{opacity:0}}>
Whilst this was effective this morning I discovered at some point during my development I had incorrectly imported Head from next/head and used this in my _document.js rather than using the correct Head from next/documents..
// import Head from "next/head"; --> incorrect
import { ServerStyleSheet } from "styled-components";
import Document, { Head, Main, NextScript } from "next/document";
Ergo -> a correctly rendering and injected element with no FOUC
Hope this helps someone out there
I've found a workaround for my small portfolio project:
just included this inline css to a <head> of my custom _document.js:
{<style dangerouslySetInnerHTML={{__html: `
html {background: #333}
body #__next div {visibility: hidden}
body.loaded #__next div {visibility: visible}
`}}></style>}
The "loaded" class is added to the body in _app.js:
if (process.browser) {
document.body.classList.add("loaded")
}
I'm hot sure if it's a good solution, any advice would be appreciated :)

Storybook MDX: Dynamic Meta Title

How can I set a dynamic title property on a Storybook Meta component in a Markdown Extended *.stories.mdx file?
import { Meta } from '#storybook/addon-docs/blocks';
// displays title as 'undefined' in sidebar nav
<Meta title={conditionalValue ? 'foo' : 'bar'} />
I also tried wrapping Meta in a higher-order component, which triggers an error: Unexpected default export without title
import { Meta } from '#storybook/addon-docs/blocks';
export const MetaCustom = (props) => {
const title = conditionalValue ? props.foo : props.bar;
return <Meta title={title} />;
};
// mdx stories file
<MetaCustom foo="foo" bar="bar" />
I tried creating a util function and import into the mdx and seems like it is working.
utils.js
export function generateTitle (condition) {
return condition ? 'foo' : 'bar'
}
Component.stories.mdx
import { generateTitle } from './utils.js';
<Meta
title={generateTitle(true)}
/>
Hope that helps!

Resources