CSSTransition not importing - type is invalid - css

I've installed react-transition-group and am calling it with:
import { CSSTransition, TransitionGroup } from 'react-transition-group'
I am then using it like this:
const PageFade = (props) => (
<CSSTransition
{...props}
classNames="fadeTranslate"
timeout={1000}
mountOnEnter={true}
unmountOnExit={true} />
)
But on mounting the app I'm getting an error when calling the component:
I've tried installing react-transition-group on both an existing project and a new one, and exactly the same thing happens.

Are you sure that all of props.children are not undefined? If you passed some undefined childern for the componet you'll get this error. Component must be string, class/function or null.

Related

Storybook fails to load story with npm link: "react is not defined" (using React 18)

I'm building a UI component library using React 18 and exporting a Button.tsx component in it.
Then, to test that I can use that Button component, i'm importing it into a different component, Test.tsx, within that same UI component library code package (using npm link) and creating a story for that component.
So Test.tsx looks like this:
import Button from 'my-component-library'
const Test = (): JSX.Element => {
return (
<>
<Button title='test' body='test' />
</>
)
}
export default Test
And this is the Story for Test.tsx:
import { Meta, Story } from '#storybook/react'
import React from 'react'
import Test from './Test'
export default {
title: 'Test',
component: Test,
} as Meta
export const Default: Story<any> = () => <Test />
But if I want to view this story, I'm getting the following error in the Storybook UI:
Couldn't find story matching 'test--default'.
- Are you sure a story with that id exists?
- Please check your stories field of your main.js config.
- Also check the browser console and terminal for error messages.
And the following error in the browser console:
Unexpected error while loading ./components/Test/Test.stories.tsx: react is not defined
ReferenceError: react is not defined
How can I fix this?

Setting up React Testing library with NextJS, GraphQL, Apollo and i18n - Cannot destructure property

As the title suggests I'm having difficulty setting up React Testing Library on a project that uses NextJS, GraphQL, Apollo and i18n
Terminal was complaining about the router not being set up so I used next-router-mock to mock it as explained in their documentation and now I'm getting this error which I can't wrap my head around
TypeError: Cannot destructure property 'pageTitle' of '_languageContent.default[locale]' as it is undefined.
// __tests__/index.test.jsx
import { render, screen } from '#testing-library/react'
import Home from '../src/pages/index'
import '#testing-library/jest-dom'
import { QueryClient, QueryClientProvider } from "react-query"
import mockRouter from 'next-router-mock';
jest.mock('next/router', () => require('next-router-mock'));
const queryClient = new QueryClient()
describe('Home', () => {
it('renders a heading', () => {
mockRouter.push("/en-US");
render(
<QueryClientProvider client={queryClient} >
<Home />
</QueryClientProvider>
)
const heading = screen.getByText('stuff');
expect(heading).toBeInTheDocument()
})
})
My assumption is that my test is not receiving the language strings it requires - the language strings are determined by the URL - http://localhost:3000/en-US for English http://localhost:3000/fr-FR for French.
On the page component itself, a languageContent const is fed a variable from useRouter to determine which strings to use
But I have tried to set the URL with mockRouter but this did nothing
Here is the component I am trying to test

Why is Vercel failing to build my Next.js tsx app?

When I run npm run build and npm start on my local machine it deploys perfectly to localhost but when I try to deploy the very same code to Vercel I get the following error:
08:28:16 Failed to compile.
08:28:16 ./pages/index.tsx:5:20
08:28:16 Type error: Cannot find module '../components/layout' or its corresponding type declarations.
It definitely seems like an issue with the Layout component, I switched around the order of the important and it always fails when trying to load the Layout component. Here's the code for the component:
import Alert from "./alert";
import Footer from "./footer";
import Meta from "./meta";
type Props = {
preview?: boolean;
children: React.ReactNode;
};
const Layout = ({ preview, children }: Props) => {
return (
<>
<Meta />
<div className="min-h-screen">
<Alert preview={preview} />
<main>{children}</main>
</div>
<Footer />
</>
);
};
export default Layout;
index.tsx line 5 looks like this import Layout from "../components/layout"; and I've confirmed that that is the correct path for the Layout component.
are you sure the file name is layout.tsx not Layout.tsx :-)
I went through the same thing.
Fix layout.tsx to Layout.tsx
The file name and component name must be the same.

React-tooltip and Next.js SSR issue

I use the react-tooltip library in my Next.js app.
I noticed that every time I refresh a website while visiting a page that uses the tooltip I get an error:
react-dom.development.js:88 Warning: Prop `dangerouslySetInnerHTML` did not match.
CSS classes are different on the client and on the server
The weird part is I do not get that error while navigating from a random page to a page that uses the react-tooltip.
The tooltip related code:
<StyledPopularityTooltipIcon src="/icons/tooltip.svg" alt="question mark" data-tip="hello world" />
<ReactTooltip
effect="solid"
className="tooltip"
backgroundColor="#F0F0F0"
arrowColor="#F0F0F0"
clickable={true}
/>
I had the same issue, I had to use state to detect when component has been mounted, and show the tooltip only after that.
P.S. You don't see the error when navigating, because the page is not rendered on server when you navigate, it's all front-end :)
In case you are using any server-side rendering (like Next.js) - you will need to make sure your component is mounted first before showing the react-tooltip.
I fixed this by using the following:
import React, { useEffect, useState } from 'react';
const [isMounted,setIsMounted] = useState(false); // Need this for the react-tooltip
useEffect(() => {
setIsMounted(true);
},[]);
return (<div>
{isMounted && <ReactTooltip id={"mytip"} effect={"solid"} />}
<span data-tip={"Tip Here"} data-for={"mytip"}>Hover me</span>
</div>)
You should wrap your JSX in the following component:
import React, { useEffect, useState } from 'react';
const NoSsr = ({ children }): JSX.Element => {
const [isMounted, setMount] = useState(false);
useEffect(() => {
setMount(true);
}, []);
return <>{isMounted ? children : null}</>;
};
export default NoSsr;
Like this:
<NoSsr>
<YourJSX />
</NoSsr>
If you are working with NEXTJS this might be a good approach, you can check the documentation here as well, also if you are working with data-event, globalEventOff or any other prop and is not hiding or not working in your localhost, this only occurs in Development Strict Mode. ReactTooltip works fine in Production code with React 18. So you can set reactStrictMode : false, in your next.config.js to test it locally and then set it back to true, hope this helps :) info reference here
import dynamic from 'next/dynamic'
const ReactTooltip = dynamic(() => import('react-tooltip'), { ssr : false });
function Home() {
return (
<div>
<Button
data-tip
data-event="click focus"
data-for="toolTip"
onClick={():void => ()}
/>
<ReactTooltip id="toolTip" globalEventOff="click"/>
</div>
)
}
export default Home

Set up Storybook to work with Next.js's Link tag

I'm trying to set up Storybook for a Next.js project. I have a component that render the Link tag from Next.js. My problem is that when I load this component, Storybook throws the following error:
Cannot read property 'pageLoader' of null
at Link.handleRef
What does one have to do to get Storybook working with Next.js Routing, specifically rendering the Link tag?
Update: Code that causes the error:
// button-component.js
import Link from 'next/link.js';
import t from 'prop-types';
import React from 'react';
function Button({ as, children, href, ...props }) {
const isExternal = href && href.startsWith('http');
const a = (
<a href={href} {...props}>
{children}
</a>
);
if (href) {
return isExternal ? (
a
) : (
<Link href={href} as={as}>
{a}
</Link>
);
}
return (
<button type="button" {...props}>
{children}
</button>
);
}
Button.propTypes = {
as: t.string,
children: t.node,
href: t.string,
};
export default React.memo(Button);
// button.stories.js
import React from 'react';
import Button from './button-component';
export default {
title: 'Button',
};
export const standardButton = () => <Button>Standard Button</Button>;
export const internalLink = () => <Button href='/buy'>
Internal Link
</Button>;
export const externalLink = () => (
<Button target="_blank" href="https://www.hopin.to">
External Link
</Button>
);
I found an issue reported about this on Next.js's github: https://github.com/zeit/next.js/issues/9951
It was reported only 5 days ago, so you could be having the same issue. The resolution is to upgrade to nextjs v9.1.8-canary.6. Reading more about this and looking at the source code, this is likely your problem. Also, there are more recent canary builds of nextjs, if you want to try something newer.
If that doesn't resolve it, my other guess is that you're getting errors because you're using Link outside of a Next.js page. Next.js may include dependencies for pages, behind the scenes. Link may rely on those dependencies and is throwing an error when they aren't found. If you want to test your components outside of Next.js pages, you could create a custom Link component that tests whether you're in Next.js and only renders Link if you are. For example:
import Link from 'next/link'
import Router from 'next/router'
const CustomLink = ({children, ...otherProps}) => {
const isPage = () => {
// if we're in a next.js route, then Router.router will be set
return Boolean(Router.router)
}
return isPage()
? (<Link {...otherProps}>{children}</Link>)
: children
}
Then use CustomLink instead of Link.
Another solution I found works similar as with next/image. To your .storybook/preview.js add following:
import Link from "next/link";
Object.defineProperty(Link, "default", {
configurable: true,
value: (props) => <a {...props} />,
});

Resources