Storybook MDX: Dynamic Meta Title - reactjs

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!

Related

Dynamic start_url

I'm fairly new to next.js, and I'm trying to create a PWA using Next.js.
The goal is to make the start_url of my pwa to be: "/recipes/:recipe_id"
I cloned this repo: https://github.com/mvllow/next-pwa-template.
Then I updated the _app.tsx file:
import type { AppProps } from 'next/app'
import { ThemeProvider } from 'next-themes'
import Meta from '#/components/meta'
import '#/styles/globals.css'
import manifest from "../public/manifest.json";
import {useEffect} from "react";
const App = ({ Component, pageProps }: AppProps) => {
useEffect(() => {
const manifestElement = document.getElementById("manifest");
const manifestString = JSON.stringify({
...manifest,
start_url: `${window.location.href}`,
});
manifestElement?.setAttribute(
"href",
"data:application/json;charset=utf-8," + encodeURIComponent(manifestString)
);
});
return (
<ThemeProvider
attribute='class'
defaultTheme='system'
disableTransitionOnChange
>
<Meta />
<Component {...pageProps} />
</ThemeProvider>
)
}
export default App
And the _document.tsx file :
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
render() {
return (
<Html lang='en'>
<link href="/manifest.json" rel="manifest" id="manifest" />
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
But the following errors occur:
anifest: property 'start_url' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'scope' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
data:application/js…:1 Manifest: property 'src' ignored, URL is invalid.
It seems like updating the file doesn't set the right format but I'm not sure.
Here are some of the links I used to update my code :
https://stackoverflow.com/a/68511528/8995872
https://medium.com/#stefanfrancis/nextjs-dynamic-manifest-be8b804ceb92
I tried updating the above code without success.
try this
start_url: `${window.location.href}`

How to both dynamically import and render a component on button click in nextjs?

I know that there are several nextjs and reactjs questions out there in this topic but I think this is specific enough to get an own thread. So I have a NextJS project where I want a button to disappear on click and then import a component dynamically and render it.
It is crucial to import the component dynamically because of 2 things.
because we work with a library in the component which relies on 'window'
because the component affects load time and we only need it when the 'init button' is clicked
Here is my index.js code so far:
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import dynamic from "next/dynamic"
import React, { useEffect, useState } from "react";
import { Inter } from "#next/font/google";
const inter = Inter({ subsets: ["latin"] });
export default function Home() {
return (
<>
<Head>
<title>My page</title>
<meta
name='description'
content="Some desc. content"
/>
<meta name='viewport' content='width=device-width, initial-scale=1' />
<link rel='icon' href='/favicon.ico' />
</Head>
<button onClick={initSurvey()}>Initialize!</button>
</>
)
}
function initSurvey(){
console.log("The button is working!")
const Survey = dynamic(() => import("../components/SurveyComponent"), {
ssr: false,
})
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Please keep in mind this is not all I could do I just cleaned up the failed attempts to deliver you a clean, readable and understandable snippet.
Thank you in advance!
By checking the React.lazy documentation and this guide, I managed to get to this solution:
import { lazy, Suspense, useState } from "react";
const dynamicComponent = lazy(() => import('../components/MyDynamicComponent');
export default function Home() {
const [dynComp, setDynComp] = useState(<div/>);
const loadDynamicComponent = () => {
return (
<Suspense fallback={<div>Loading...</div>}>
<dynamicComponent/>
</Suspense>
)
}
return (
<>
<button onClick={ () => setDynComp(<div>{loadDynamicComponent()}</div>)}>Initialize!</button>
{ dynState }
</>
);
}
Test it and let me know if it helps you!

React framework Remix Prop className did not match [duplicate]

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!

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 ;

Resources