I have a data file api that has bunch of images url stored locally
const url =[
{ title:img1,
img_src="./img/img1.png"
},
{ title:img2,
img_src="./img/img2.png"
},
{ title:img3,
img_src="./img/img3.png"
}
]
And using react/redux I pass the url state as props to my react components.Next I want to display them in my components by using require
<img src=require(?)/>
What's the appropriate syntax here? I've used es6 template string ${this.props.urls.img_src} but it throws an error that it couldn't resolve the path. I've tried to require("./img/img1.png") just to test to rule out broken path and it worked. But still wouldnt work if you reference it using a prop.
Solution
After researching, and thanks to Rei Dien for the input, I now can use variables in require by using context require
<img src={require("./img/"+this.props.img_src)}/>
Since you passed the url in the props, you can do this :
this.props.url.map(n => {
return (
<img src={n.img_src}/>
)
})
this will diplay all the images.
since require works in static mode during build process on node only so follow following steps.
1) take all image urls and store them in a javascript file
so
//imageURLs.js
import image1 from "path_to_image_file_1";
import image2 from "path_to_image_file_2";
import image3 from "path_to_image_file_3";/**do like this for all images stored locally, image1, image2,.. are the image identifiers(title in your case) you would get in api call**/
export const urls = {image1, image2, image3};
//image usage file
read api for identifier and
import imageURLs from './imageURLs.js';
<img src={imageURLs[image_id_from_api]}/>
Related
I'm using rollup to bundle a react npm package that contains an icon component that takes a name as a prop and returns an Icon with that name wrapped by a react component.
This is the component code:
import sprite from './public/sprite.svg';
function Icon({ name }) {
return <svg className="svg-wrapper">
<use href={`${sprite}#${name}`} />
</svg>
);
}
The folder structure is the following:
- src
- - public
- - - sprite.svg
- - icons
- - - some-icon.svg
- - - some-other-icon.svg
- - index.tsx # component with the code mentioned above
And this is my rollup config:
export default {
plugins: [
esbuild({
sourceMap: false,
target: "esnext"
}),
image(),
svgicons({
inputFolder: "src/icons",
output: "public/sprite.svg"
}),
json()
]
}
This works fine in Chrome (although it does inline all the svg inside of the href which I think it's the purpose of this approach) but in Safari it triggers the following error:
Unsafe attempt to load URL data:image/svg+xml,%3c%3fxm ....
Domains, protocols and ports must match.
The thing is, as mentioned, this is an npm package that packages the icons as part of the js bundle (inlining) so there's not much control over how this component is served since this is handled by the browser caching (also one of the key points of using this approach). I'm quite familiar with CORS and I know that perhaps avoiding to use data:image/svg+xml uri links would fix this but would increase the complexity of the build steps of this package (needing to build the icons using svgr/svgo and then have some kind of lookup table to give back the right icon based on the name prop i.e.).
So, ultimately my question is, with the sprite approach in a react component library is there a foolproof way of avoiding these kind of issues and cross-browser inconsistencies?
Thanks in advance for any help provided.
I have been struggling with this issue for a while. I guess this is a bug on Safari throwing an error because is dealing with a dataURI as if it was an external URL.
About your code, you could expose your sprite in a public folder or publish it in a cdn (good for caching purposes) and change the way rollup is handling your svg (it seems it is packing your svg as a dataURI). Alternatively, I implemented a workaround to convert the dataURI in a blob.
import sprite from './public/sprite.svg';
function dataURItoBlobUrl(dataURI: string) {
const svg = decodeURI(dataURI).split(',')[1];
const blob = new Blob([svg], { type: "image/svg+xml" });
return URL.createObjectURL(blob);
}
const blobUrl = dataURItoBlobUrl(sprite);
export const Icon: FC<IconProps> = ({ name, ...props }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" {...props}>
<use href={`${blobUrl}#${name}`}></use>
</svg>
);
};
I'm getting this error: InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('/static/media/showcaseimage.c2c0ae9f.jpg') is not a valid name.
Why do I get it on an image import ? (I'll include my file tree. but i think the issue is not with that). The name of the image inside of the image folder is showcaseimage.jpg
my file tree and how i imported an image inside of my component
Imported images are not components, they are URLs (or they will be by the time a bundler has worked its magic).
You need an img element or other thing that accepts a URL to use it.
import myImage from '../images/foo.jpeg';
const MyComponent = () => {
return <img src={myImage} alt="Alternative text goes here as usual" />;
}
I want to use file-viewer in Next.js, but I get this error:
./public/pdf.pdf Module parse failed: Unexpected token (1:0) You may
need an appropriate loader to handle this file type, currently no
loaders are configured to process this file. See
> %PDF-1.3
| %����
|
How can I solve this problem?
my code:
import FileViewer from "react-file-viewer/src/components";
import pdf from "../../../public/pdf.pdf"
...(in component)
{openFileViewer ? <FileViewer fileType="pdf" filePath={pdf} /> : null}
Since your PDF file is located in the public folder, you can reference the image's path directly in the filePath prop.
You also need to make sure react-file-viewer is only imported in the browser as it depends on window being present to work properly. You can do so by dynamically importing the component through next/dynamic with ssr: false.
import dynamic from 'next/dynamic';
const FileViewer = dynamic(() => import('react-file-viewer'), {
ssr: false
});
export default function Index() {
return (
<FileViewer fileType="pdf" filePath="/pdf.pdf" />
);
};
You still can import a .pdf file in Next.js without the need to a third party module, simply by using <iframe> HTML tag instead.
If you uploaded your file on a cloud storage; say google drive, dropbox, S3 ..etc
you can embed its link in your website as such:
const PreviewFile = () => {
return (
<iframe
src="https://drive.google.com/file/d/11h3WlhD221wMuXyXWPsdmXb4UNM-qaot/preview"
title="Async & Performance"
width="800"
height="600"
/>
)
}
*Note that a google drive link is used here but it's an embed link not the one you get when you click on share button.
as attached below:
How to show images? It can not be shown correctly below.
In the src/components/Header.js file:
<img src="../images/logo.png" style={{width:"112",height:"28"}} />
Importing Assets Directly Into Files
import React from "react"
import logo from "./logo.png" // Tell Webpack this JS file uses this image
console.log(logo) // /logo.84287d09.png
function Header() {
// Import result is the URL of your image
return <img src={logo} alt="Logo" />
}
export default Header
The reason this is best is that it enables optimizations through the Webpack bundling pipeline, e.g. compression, data URLs, cache busting filename hashes, etc.
Using the Static folder
This is mostly useful for files other than images.
You can create a folder named static at the root of your project.
Every file you put into that folder will be copied into the public
folder. E.g. if you add a file named sun.jpg to the static folder,
it’ll be copied to public/sun.jpg
You can reference assets from the static folder in your code without
anything special required:
render() {
// Note: this is an escape hatch and should be used sparingly!
// Normally we recommend using `import` for getting asset URLs
// as described in the “Importing Assets Directly Into Files” page.
return <img src={'logo.png'} alt="Logo" />;
}
Corey's answer quotes the "Add custom webpack config" section of the Gatsby documentation, which is useful but unnecessary to load images.
Create a gatsby-node.js file at the root of your project if you don't already have one and add this:
const path = require("path")
exports.onCreateWebpackConfig = ({ stage, actions }) => {
actions.setWebpackConfig({
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"],
alias: { react: path.resolve("./node_modules/react") },
},
})
}
This does two things:
It will make src the base for your imports
It will ensure that you don't run into weird bugs due to multiple versions of React getting loaded (plugins that need to reference React can cause this).
In your Header.js file, you can now do this:
import logo from "images/logo.png"
export const Header =>
<header>
<img src={logo} alt="Logo Alt Text" />
</header>
The rendered result of this will actually be different depending on the file size of your logo. If it's small enough, Gatsby will inline it using base64, reducing the number of HTTP requests required to load your page. If it's larger, it will be given an asset fingerprint and added to the assets available when your site is built and the URL to the file will be used for the src attribute (e.g. /images/logo-123asd.png). This will allow you to use HTTP cache headers that tell the browser it's safe to cache this file for a long time; if it changes, the URL will change and you don't need to worry about invalidating the cached version.
So i have a visual studio project created with react.js.
I am trying to link to an image dynamically, but failing. This is the code I am trying:
At the top im setting a variable for the first part of the path:
this.LogoPath = '../images/'
And then im dynamically grabbing the name of the image from an api call.
this.setState({ imageNamePath: this.state.location.imageName })
And then im concatinating them:
{`${this.LogoPath}${this.state.location.imageName}`}
In the console, im getting:
img src='../images/the-images-name-here.png'
So it seems to be working, but it is not. I get no errors, and I have broken images. My best guess is that react is changing the images to something like:
image-name-here.6a131799.png
Surely someone has run across this before, but my google search pulled up little help.
So how do i get the images to show?
Webpack is a smart tool. One of it's strength is the trash code/files elimination from the bundle.
That means that if a file is not imported using import myFile from '../myPath/myFile.jpg'; or require('../myPath/myFile.jpg');` it won't be a part of the final bundle.
In your case you're not importing the file. You're creating a string variable instead which means nothing to webpack.
There are different options that could work in your case:
Option 1: Pre-import all images and map them in an object:
import React, {Component} from 'react';
import image1 from '../assets/image1.png';
import image2 from '../assets/image2.png';
import image3 from '../assets/image3.png';
const imageTypes = {
image1,
image2,
image3,
}
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
imageType: 'image1'
}
}
render() {
return (
<img src={imageTypes[this.state.imageType]} />
)
}
}
Option 2: Not recommended - Use require to dynamically import files (webpack configurations might be needed in order to include all possible required images in the production bundle):
class MyComponent {
constructor(props) {
super(props);
this.state = {
image: 'file1.png'
}
}
render() {
return (
<img src={require(`./assets/${this.state.image}`)} />
)
}
}
Option 3: Send the image blob (in base64) from the API.
I suggest you to use the Option 1 or Option 3, based on your requirements, such as: how often will be images be changed/added/removed. It's not normal to import files dynamically from ReactJS bundle and you might end up having a non-existing image in your project requested by the data coming from an external source.
For Option 2 you also might have some problems configuring the webpack in order to include in the bundle all the images that you'll probably need to render, even though they are not imported (hardcoded) somewhere in the JS files. Keep in mind that the React Application in production ends up being a collection of static files. You'll need to treat them as follows.