How to get image height and width properties in Next.js? - next.js

I just want to know how can we let an image take its own height and width using <Image> component in Next.js, instead of defining height and width by ourselves?

Beginning from Next.js v11, you can simply do:
import Image from 'next/image';
import foo from 'path/to/foo.png';
// ...
<Image src={foo} alt="" /> // <-- no need to pass height/width
In the above example, foo will be an object containing src, height, width (and optionally blurDataURL). So, if you want to access them, you can do stuff like foo.height, etc.
Also, there are a few hacks that may interest you:
Use layout="fill" and pass a handler to onLoadingComplete, where you will get naturalWidth and naturalHeight. Then you can set the state to adjust the container accordingly. But this approach is not recommended as it will likely increase CLS.
In data fetching methods [getStaticProps (static generation) / getServerSideProps (SSR)], read your image files and pass their dimensions as a prop to your components. SSR may cause an overhead on your server resources, but that can be minimized significantly by caching.
Simply use your good old img tag. Again not recommended, but will work if your files are already optimized. ESLint may throw some warning depending on your configuration, you would need to disable those rules.
PS: Just check once if your use-case can be handled by layout="fill" (without updating state).
Just a clarification - on older threads on SO, GitHub, etc., you may see an unsized prop being passed to next/image. It was deprecated in Next.js v10, and removed in v11. So, its probably not gonna work for you.
References:
https://nextjs.org/docs/api-reference/next/image
https://nextjs.org/docs/basic-features/data-fetching
https://nextjs.org/docs/going-to-production
Get the width and height of an image in node.js
Next.js build fails using <img> tag
How to use Image component in Next.js with unknown width and height
https://web.dev/cls
https://web.dev/time-to-first-byte
A sample implementation of the second hack:
import fs from "fs";
import path from "path";
import Image from "next/image";
import probe from "probe-image-size";
const IndexPage = ({ mountains }) => (
<Image
src="/mountains.jpg"
height={mountains.height}
width={mountains.width}
alt="Mountains"
/>
);
const getStaticProps = async () => {
const mountains = await probe(
fs.createReadStream(path.join(process.cwd(), "public/mountains.jpg"))
);
return { props: { mountains } };
};
export default IndexPage;
export { getStaticProps };

Related

nextjs Image property null

I have a component with dynamic content like so :
<Image width="680" height="400" src={post.imgsrc} alt={post.title} />
I keep having the same error even if I have added the width/height :
Image with src "/imgs/paintings/2022/2.jpg" must use "width" and "height" properties or "layout='fill'" property.
I don't know why, and I wonder why I have to specify width and height since my pictures have different sizes...
One thing to mention is that you can import the images if they are local, if you want that you do not need to use width, height, or fill.
They get provided automatically
Example from the docs:
import profilePic from '../public/me.png'
import Image from 'next/image'
import profilePic from '../public/me.png'
function Home() {
return (
<>
<h1>My Homepage</h1>
<Image
src={profilePic}
alt="Picture of the author"
// width={500} automatically provided
// height={500} automatically provided
// blurDataURL="data:..." automatically provided
// placeholder="blur" // Optional blur-up while loading
/>
<p>Welcome to my homepage!</p>
</>
)
}
This also explains why remote images do need these properties.

Keeping react-player full-screen mode between videos

I am building an online course website.
When the user watches a lesson in full-screen mode, I want to remember that, so as to use full-screen mode when I mount react-player with the next lesson. I hoped there would be an onFullscreenMode callback, but the documentation does not list anything of the kind. How can I achieve this?
Edit 1: Based on the reply of #onkarruikar, I tried using screenfull. First, I was surprised that it was not installed although real-player was supposed to use it to enter full-screen mode. After installing the package and importing it, I get the compilation error:
.../node_modules/screenfull/index.js 11:44
Module parse failed: Unexpected token (11:44)
File was processed with these loaders:
.../node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|
| for (const methodList of methodMap) {
> const exitFullscreenMethod = methodList?.[1];
|
| if (exitFullscreenMethod in document) {
Edit 2: I also don't get it why the demo uses a custom button for switching to full-screen mode, whereas I see a button () on the player itself:
The player doesn't have fullscreen inbuilt. It uses screenfull to go full-screen. As per their demo https://cookpete.com/react-player/ full-screen is handled externally by the component users.
You can use following screenfull features directly on your website:
screenfull.isFullscreen //<-- is the browser in fullscreen
screenfull.isEnabled //<-- is the facility available to use
screenfull.request(element);
screenfull.toggle(element);
etc.
Or you can use standard web apis like:
if(document.fullscreenElement) { //<-- is the browser in fullscreen
...
}
document.fullscreenEnabled //<-- is the facility available to use
Document.fullscreenElement / ShadowRoot.fullscreenElement
The fullscreenElement property tells you the Element that's currently being displayed in full-screen mode on the DOM (or shadow DOM). If this is null, the document (or shadow DOM) is not in full-screen mode.
ref
These apis should work even if you go fullscreen using controls inside player.
Here is a demo website using react: https://gizcx.csb.app/
Corresponding codesandbox code
Also, if you are not playing videos one by one then you can pass full course playlist to the player at once:
<ReactPlayer
url={[
'https://www.youtube.com/watch?v=oUFJJNQGwhk',
'https://www.youtube.com/watch?v=jNgP6d9HraI'
]}
/>
For the benefit of others, this is how it is achieved:
import { findDOMNode } from 'react-dom'
import { toast } from 'react-toastify';
const PlayerComponent = () => {
const [fullscreenMode, setFullscreenMode] = useState(false)
let player = null;
const ref = (p) => {player = p;}
const onStart = () => {
if (fullscreenMode)
findDOMNode(player).requestFullscreen().catch(
(err) =>
{toast.error("Could not activate full-screen mode :(")}
);
}
const onEnded = () => {
setFullscreenMode(document.fullscreenElement !== null);
}
return (
<ReactPlayer
ref={ref}
url="whatever url"
onStart={onStart}
onEnded={onEnded} />);
);
}

Material-UI - why different css is shown on prod environment then development env

I use material UI (verison: ^4.12.3) Select, with custom input.
For some reason the prod env Select input has a black background and :before element with white background.
I don't know from where it comes from.
this is image of the prod:
this is image of the dev Select:
when comparing the 2 css & html of the envs Select element, it's is shown that there is a ::before element added in prod that is not presented in dev
also, the background color is different. in prod there is another class added to the InputBase element, which doesn't exist in dev. this class adds a background-color black:
Edit 1
it seems like MUI inject <style>. in the prod html i see the background-color: black and the ::before. ill try adding the index solution, but my problem is not precedence (the style that i do use override the injected style). also, it wont help the ::before element. how to disable the injected styles ? or work around it ?
the injected bad css:
Please refer to this question. As answered by user Mordechai.
It seems like webpack could mess with MUI's rules on JSS precedence... This could be solved by adding an index of one to MUI's methods.
//Hook
const useStyles = makeStyles({
// your styles here
}, {index: 1})
// HOC
MyComponent = withStyles({
// your styles here
}, {index: 1})(MyComponent)
adding <StylesProvider /> wrapper to the app fixed it. we use micro-frontend infrastructure. and one of the frontends app also had makeStyles. this is causing classNames conflicts in MUI.
in the root component <App/>:
import {
StylesProvider,
createGenerateClassName
} from '#material-ui/core/styles';
const generateClassName = createGenerateClassName({
seed: 'app1'
});
const App = () => {
return (
<StylesProvider generateClassName={generateClassName}>
<OtherAppComponents />
</StylesProvider>
)
}
if you have more then 2 add a provider and a generator to each, with different seed

How to test React dynamic style prop?

Am teaching myself React and am starting on testing. Using the recommended stuff from the docs... create-react-app, jest, testing-library/react. I have a component that renders a dynamic style, something like this
const ScalingDiv = (props) => (
<StyledDiv size={props.size || 42}>
<OtherEl>
{props.text}
</OtherEl>
</StyledDiv>
);
I would like to verify that my logic in there is working correctly (that 42 is used as a fallback size). I cannot find any examples or docs of this. I had hoped that something like this would work-
test('check fallback size', async () => {
const {container} = render(<ScalingDiv/>);
expect(container.firstChild).toHaveAttribute('size', 42);
});
But I haven't found any combination of matchers and queries that returns ANY attributes. Then I tried to just check the style directly using jest-dom, but toHaveStyle('this_isnt_valid_css: 199') passes- I couldn't stick anything in there to get it to fail. So... what is the right way to do this?
It's not attribute but prop. So we can refer to prop() and props() methods like
expect(container.firstChild.prop('size')).toEqual(42);
or
expect(container.firstChild.props()).toEqual({
size: 42
});

NextJS - react-springy-parallax doesn't work

I'm trying to use react-springy-parallax in my NextJS project, but whenever I want to use it, I get the following error message:
Fetch API cannot load webpack://%5Bname%5D_%5Bchunkhash%5D/./node_modules/react-dom/cjs/react-dom.development.js?. URL scheme must be "http" or "https" for CORS request.
Is this is a limitation to react-springy-parallax on NextJS?
Here is the example code I put in my index.js component:
<Parallax ref='parallax' pages={3}>
<Parallax.Layer offset={0} speed={0.5}>
<span>Layers can contain anything</span>
</Parallax.Layer>
</Parallax>
It seems the problem has something to do with a CORS issue and I don't know exactly how to approach a solution to this problem.
I've read that this has nothing to do with NextJS in particular. After React 16.8.0 and up, I read that I have to use the useRef function.
Solution:
import React, { useRef } from 'react'
[...]
const parallax = useRef( 'parallax' )
[...]
<Parallax ref={ parallax } pages={3}>
<Parallax.Layer offset={0} speed={0.5} onClick={ () => parallax.current.scrollTo(1) }>
<span>Layers can contain anything</span>
</Parallax.Layer>
</Parallax>
Next Js has no problem with next Js. First initialize a variable to use as useRef
const parallax = useRef(null!)
Then you can start creating the parallax component and you should use the ParallaxLayer component instead of Parallax.Layer component
<Parallax pages={3} ref={parallax}>
<ParallaxLayer offset={0} speed={0.5}>
<span>Layers can contain anything</span>
</ParallaxLayer>
</Parallax>
This will solve the problem, if you need example, check out this code,
parallax in next JS

Resources