I want to create an app that shows different songs i've chosen, with react.js
The problem is that it doesn't work with local files. Path is ok (just checked in the DOM)
I've tried with relative path and absolute path but it is still the same.
I've tried a lot of things, such as importing react-sound, react-audio-player...
I've tried to directly import the mp3 file at the beginning of the file with "import song from "./songs/song.mp3" and it works, but it is useless as you have to add it manually if you want to add/delete songs.
When I press the play button, it always fails the promise and returns me the error :
DOMException: Failed to load because no supported source was found.
import React from "react";
const SongCard = (props) => {
const playAudio = () => {
const audio = new Audio(props.song.path)
const audioPromise = audio.play()
if (audioPromise !== undefined) {
audioPromise
.then(() => {
// autoplay started
console.log("works")
})
.catch((err) => {
// catch dom exception
console.info(err)
})
}
}
return (
<div className="songCard">
<div className="coverContainer">
<img src=""/>
</div>
<div className="infoContainer">
<div className="playPauseButton" onClick={playAudio}>►</div>
<div className="songTitle">{props.song.nom}</div>
</div>
</div>
);
};
export default SongCard;
Does anyone have an idea ?
Due to security issues, you won't be able to access local files programatically from JavaScript running in browser.
The only way you can get a hold of local files is by:
User selecting the file via a file <input>
User drag and dropping the files into your application
This way the user is explicitly giving you access to those files.
You can either design your application around those interactions, or
You can start a web server locally where it has access to your audio files and stream those to your app or upload the files to a cloud service.
you can do it by using this code:
const SongCard = (props) => {
const playAudio = () => {
let path = require("./" + props.song.path).default;
const audio = new Audio(path);
const audioPromise = audio.play();
if (audioPromise !== undefined) {
audioPromise
.then(() => {
// autoplay started
console.log("works");
})
.catch((err) => {
// catch dom exception
console.info(err);
});
}
};
return (
<div className="songCard">
<div className="coverContainer">
<img src="" />
</div>
<div className="infoContainer">
<div className="playPauseButton" onClick={playAudio}>
►
</div>
<div className="songTitle">{props.song.nom}</div>
</div>
</div>
);
};
export default SongCard;
it'll work if you change the "./" in the require to the relative path of the audio's dictionary, and send only the name of the audio file in the parent's props
I hope I was help you
Related
I don't know, I've imported local images before but it isn't working today.
I have this helper file which exports the images as an array
const images = [
require("../assets/1.jpeg"),
require("../assets/2.jpeg"),
require("../assets/3.jpeg"),
require("../assets/4.jpeg"),
require("../assets/5.jpeg"),
require("../assets/6.jpeg"),
]
export default images;
Then I use them here to get a random image here
//Random Image
const randomImg = () => {
console.log(images);
const UU = images[Math.floor(Math.random * images.length)];
return UU;
}
const [hero, setHero] = useState(randomImg());
And then I get hat hero state in my jsx img tag
<img
className="headerImg"
src={hero}
alt="Hero Image"
/>
Why Isn't it working. I'm not using Next or gatsby or anything. I'm using React with webpack 2. Anyone know what is wrong?
Another interesting thing is that if I import a single image like this
import hero from "../../assets/1.jpeg";
And Use It directly in the image
<img
className="headerImg"
src={hero}
alt=""
/>
Suddenly, it works. What is the Problem?
Thanks,
Lakshya
I was trying to resolve this problem, but I have no luck...
I'm using React and 'react-bootstrap'. Getting data from firebase with useState, as you can see in the next code. But also I'm calling a modal as a component, and this modal use useState to show and hide the modal.
export const Models = () => {
const [models, setModels] = useState(null);
useEffect(() => {
firebase.database().ref('Models').on('value', (snapshot) => {
setModels(snapshot.val())
});
}, []);
return models;
}
the problem result when I click on the url to access the modal, this one is shown and the main component goes to firebase and tries to get the data again. So, if I click 3 times on the modal, I will get my data from firebase 3 times.
How can I fix this? to get my data from firebase only one time, regardless of the times that you open the modal window?
The other part of the code
const Gallery = () => {
const [fireBaseDate, setFireBaseDate] = useState(null);
axios.post('https://us-central1-models-gallery-puq.cloudfunctions.net/date',{format:'DD/MM/YYYY'})
.then((response) => {
setFireBaseDate(response.data)
});
let content = Models();
let models = [];
const [imageModalShow, setImageModalShow] = useState(false);
const [selectedModel, setSelectedModel] = useState('');
if(content){
Object.keys(content).map((key, index) =>
models[index] = content[key]
);
models = shuffleArray(models);
console.log(models)
return(
<div className="appContentBody">
<Jumbo />
<Promotion models={models}/>
<div className="Gallery">
<h1>Galería - Under Patagonia</h1>
<Filter />
<div className="img-area">
{models.map((model, key) =>{
let myDate = new Date(model.creationDate);
let modelEndDate = new Date(myDate.setDate(myDate.getDate() + 30)).toLocaleDateString('en-GB')
if(fireBaseDate !== modelEndDate && model.active === true){
return (
<div className="img-card filterCard" key={key}>
<div className="flip-img">
<div className="flip-img-inner">
<div className="flip-img-front">
<img className="single-img card-img-top" src={model.thumbnail} alt="Model"/>
</div>
<div className="flip-img-back">
<h2>{model.certified ? 'Verificada!' : 'No Verificada'}</h2>
<p>Número: {model.contact_number}</p>
<p>Ciudad: {model.city}</p>
<p>Servicios: {model.services}</p>
</div>
</div>
</div>
<h5>{model.name}</h5>
<Button variant="danger" onClick={() => {
setImageModalShow(true)
setSelectedModel(model)}
}>
Ver
</Button>
</div>
);
}
return 0})}
</div>
<Image
show={imageModalShow}
onHide={() => setImageModalShow(false)}
model={selectedModel}
/>
</div>
<Footer />
</div>
)} else {
return (
<div className="loading">
<h1>Loading...</h1>
</div>
)}
}
export default Gallery;
Thanks for your time!
Models is a regular javascript function, not a functional component. So this is not a valid use of hooks, and will not work as expected. See docs on rules of hooks.
A functional component receives props and returns JSX or another React element.
Since it does not, it is basically restarting and calling your effect each time its called by the parent.
Looking at your edit, you should probably just remove the Models function and put the logic in the Gallery component.
The way I read your above component makes it seem like you've defined a custom hook for getting data from firebase.
So first off, I would rename it to useFbData and treat it as a custom hook, so that you can make use of the ESLint Plugin for Hooks and make sure you're following the rules of hooks.
The way you have this above, if it's a function within a component, your function will fire on every render, so the behaviour you are describing is what I would expect.
Depending on how expensive your request is/how often that component renders, this might be what you want, as you probably don't want to return stale data to your component. However, if you feel like the response from the DB should be cached and you have some logic to invalidate that data you could try something like this:
import { useEffect, useRef } from 'react';
const useFbData = invalidationFlag => {
const data = useRef(null);
useEffect(() => {
if (!data.current || invalidationFlag) {
firebase.database().ref('Data').on('value', (snapshot) => {
data.current = snapshot.val();
});
}
}, [invalidationFlag]);
return data.current;
};
export default useFbData;
This way, on the initial run and every time you changed the value of invalidationFlag, your effect inside the useFbData hook would run. Provided you keep track of invalidationFlag and set it as required, this could work out for you.
The reason I used a ref here instead of state, is so that the effect hook doesn't take the data in the dependency array (which would cause it to loop indefinitely if we used state).
This will persist the result of the db response between each call and prevent the call being made multiple times until you invalidate. Remember though, this will mean the data you're using is stale until you invalidate.
I'm currently rendering a child component when a signInError occurs. The signInError is stored in the parent component and if it's not null, it renders the <SignInError/> component, as per the code below:
ParentComponent.js
// Some code...
render() {
return(
<div>
<SignInForm
doSignIn={this.doSignIn}
resetSignInError={this.resetSignInError}
signInError={this.state.signInError}
/>
{this.state.signInError && <SignInError/>}
</div>
);
}
So far, so good, here's the child component SignInError.js
import React from 'react';
import RoundImage from '../../../UI/Common/RoundImage';
import Newman from '../../../../assets/newman-min.png';
class SignInError extends React.Component {
constructor(props){
super(props);
}
componentDidMount(){
const img = new Image();
img.src = Newman;
}
render(){
return(
<div>
<div>
<RoundImage src={img.src}/> // <--- img is undefined here!!!
</div>
<div>
Hello... Newman!
</div>
</div>
);
}
}
export default SignInError;
RoundImage.js
import React from 'react';
const RoundImage = (props) => {
return (
<div>
<img src={props.src}/>
</div>
);
}
export default RoundImage;
How to preload images in React.js?
This question's answer (link above) here on Stack Over flow tells me to create the img object inside the componentDidMount() method to force the browser to load it. And so I did, as you can see from the code above. But now, when I try to pass it as a prop to my grand-child component inside my render method, I can't access the img, because it was defined inside of another method.
What's the best way around this? I just need the image to be loaded and to be displayed together with the error message. Otherwise the error message will show before the image, if your browser hasn't cached it yet. Thanks for the help.
Image download happens in the browser. Rendering to the DOM also happens in the browser.
By preloading, do you mean that you want that the component renders only when the image is ready?
If so, you could do something like this:
componentDidMount() {
const img = new Image();
img.onload = () => {
// when it finishes loading, update the component state
this.setState({ imageIsReady: true });
}
img.src = Newman; // by setting an src, you trigger browser download
}
render() {
const { imageIsReady } = this.state;
if (!imageIsReady) {
return <div>Loading image...</div>; // or just return null if you want nothing to be rendered.
} else {
return <img src={Newman} /> // along with your error message here
}
}
A bit of a different approach, but if you have the image source in advance, you can add the image source to the main html file as a link ref with preload option. The browser will preload the image (with relatively low priority) and at the time your app will load the image, it should be cached in the browser memory.
<head>
..
..
<link rel="preload" href="<your_image_source_here>" as="image">
...
</head>
In this approach, we separate the preloading process from the code. It is more relevant when you have the image source in advance (and not dynamically) and when you don't need to cache a large amount of images (will be a bit messy to add a large list of links in the html head, although possible)
you can learn more about link preloading here: Preloading content with rel="preload"
In my case I start with an initial src attribute for my images and wanted to delay changing them after the image has been loaded by the browser, so I wrote the following hook in Typescript:
import { useEffect, useState } from 'react';
export const useImageLoader = (initialSrc: string, currentSrc: string) => {
const [imageSrc, _setImageSrc] = useState(initialSrc);
useEffect(() => {
const img = new Image();
img.onload = () => {
_setImageSrc(currentSrc);
};
img.src = currentSrc;
}, [currentSrc]);
return [imageSrc];
};
I'm trying to do an asynchronous read in usb with fork() from the child_process module in electron. That is to say, when I click a div (id="read") a message is sent from the renderer process to the main process, which then in response calls fork() and reads in data from USB asynchronously. To handle usb communications I'm using the node-serialport library.
index.html
<html>
<head>
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="scroll.css">
<link href="https://fonts.googleapis.com/css?family=Questrial" rel="stylesheet">
</head>
<body>
<div id="ui-container">
<div id="top-bar" class="shadowed">
<div id="top-bar-left-decoration"></div>
<div id="close-app" class="top-bar-button"><div class="unselectable top-button-text">x</div></div>
<div id="maximize-app" class="top-bar-button"><div class="unselectable top-button-text">□</div></div>
<div id="minimize-app" class="top-bar-button"><div class="unselectable top-button-text">-</div></div>
</div>
<div id="navigation-bar">
<div id="deviceSelection" class ="unselectable navigation-button">
<img id="deviceSelection-image" class="navigation-image" src="Icons/selectDevice2.png">
</div>
<div id="info" class="unselectable navigation-button">
<img id="info-image" class="navigation-image" src="Icons/DeviceInfoNoBorder.png">
</div>
<div id="config" class=" unselectable navigation-button">
<img id="config-image" class="navigation-image" src="Icons/DeviceConfigNoBorder.png">
</div>
<div id="graph" class="unselectable navigation-button">
<img id="graph-image" class="navigation-image" src="Icons/DataViewNoBorder.png">
</div>
<div id="export" class="unselectable navigation-button">
<img id="export-image" class="navigation-image" src="Icons/Export.png">
</div>
<div id="options-container"><img id="options" src="Icons/options.png"></div>
</div>
<div id="information-data-view" class="unselectable">
<div id="data">
<div id="push-to-read"></div>
</div>
</div>
</div>
</body>
<script src="ipcRenderer.js" type="text/javascript"></script>
</html>
This is my index.js, responsible for creating the browser window
const electron = require('electron')
const ipcMain = require('electron').ipcMain
const url = require('url')
const path = require('path')
const child_process = require('child_process')
const app = electron.app
var windowFullScreen = false;
const BrowserWindow = electron.BrowserWindow
var MainWindow;
app.on('ready', function()
{
MainWindow = new BrowserWindow({
width: 1024,
height: 768,
backgroundColor : '123355',
frame: false,
resizable: true,
movable: true,
show: false
})
MainWindow.on('ready-to-show', () => {
MainWindow.show()
console.log('Ready to go!')
})
MainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
ipcMain.on("minimize", (event, arg) => {
MainWindow.minimize()
console.log("minimize")
})
ipcMain.on("maximize", (event, arg) => {
if (!windowFullScreen) {
MainWindow.maximize()
windowFullScreen = true;
}
else {
MainWindow.setSize(800, 600)
windowFullScreen = false;
}
console.log("maximize")
})
ipcMain.on("close", (event, arg) => {
MainWindow.close()
console.log("close")
})
ipcMain.on("read", (event, arg) => {
setInterval(()=>{console.log(usbcomm.read(1))}, 1)
const process = child_process.fork('./readUSB.js')
})
})
ipcRenderer.js
This is where I set up onclick event handlers for the DOM. The relevant part here is read.onclick() which sends "read" message to the main process telling it fork the process and run readUSB.js which I've included below.
const electron = require('electron');
const ipcRenderer = electron.ipcRenderer;
var minimize = document.getElementById("minimize-app");
var maximize = document.getElementById("maximize-app");
var read = document.getElementById("push-to-read");
var close = document.getElementById("close-app");
minimize.onclick = (event) => {
ipcRenderer.send("minimize", "an-argument")
console.log("minimize");
}
maximize.onclick = (event) => {
ipcRenderer.send("maximize", "an-argument")
console.log("maximize")
}
close.onclick = (event) => {
ipcRenderer.send("close", "an-argument")
console.log("close")
}
read.onclick = (event) => {
ipcRenderer.send("read", "an-argument")
console.log("read")
}
readUSB.js
this code should simply read a byte from USB and output it to console, what it does instead is to read nothing, and output null (usbcomm.read() returns null if it didn't read anything). This is just a proof of concept to make sure I can read() asynchronously, but things are obviously not working correctly.
const SerialPort = require('serialport')
const usbcomm = new SerialPort("COM4")
usbcomm.setEncoding('utf-8')
usb_rx();
function usb_rx()
{
console.log("running in child process!")
console.log(usbcomm.read(1))
}
if I run this code as an event handler in response to a "read" message from the renderer process, everything runs normally and I read correct responses from usb. I've confirmed this is not a problem with my usb device, and that in simple use cases usbcomm.read() behaves as expected.
I'm wondering now if node-serialport for whatever reason won't work with code run inside of fork().
You can make blocking calls from a renderer. As long as you keep them below 20-30ms and you don't swamp the process with blocking calls you'll be fine. We've used node-serialport and node-ffi extensively in the renderer process making dozens of calls per second transferring megabytes of data while keeping the UI responsive with no jerkiness.
Maybe you can't keep the blocking calls short enough? How about doing it in the main process? This is also a bad idea. Blocking the main process blocks IPC between the renderers and GPU process so you'll likely hang the UI this way too.
If you really have to make long blocking synchronous calls, make them in a hidden renderer process. You can block this as much as you like because it's not displaying any UI. To make this easier, you can use electron-remote - renderer-taskpool feature to bump long running tasks onto another renderer process.
I have a React + Rails app and the current S3 server issues made me realize that I don't have a proper fallback mechanism when data can't be pulled from s3. I'm trying to make it work with my locally stored images for the moment and I plan on adding it the same way to my other image tags.
My img is as follows:
errorLink() {
this.onError = null;
this.src = '/img/icons/static/credentials.svg';
}
<img alt="Icon for credentials and experience" src="/img/icons/static/credentials123.svg" onError={this.errorLink.bind(this)()}/>
the src inside the image pointing to credentials123.svg is a dummy and I've added it specifically to raise the error. But it's not updating the src of my image. How can I achieve this in react? I'd rather not show broken image links to my users next time during an Amazon outage
One of the many many solutions (since it is really based on your inner React project structure). You just keep your image url in a state somewhere as a default image. Once you get your proper image url from S3 then you will replace default one in state with a new one you got.
const DEFAULT_IMAGE = '/img/icons/static/default.svg';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
url: DEFAULT_IMAGE
};
}
render() {
return (
{/* ... some UI here ... */}
<img
alt="Icon for credentials and experience"
src={this.state.url}
/>
);
}
// ....
_someAsync = () => {
// some async logic here
// In here in 5 seconds state will be updated by replacing default url
// with new url image link
setTimeout(() => this.setState({
loaded: true,
url: '/img/icons/static/credentials.svg'
}), 5000);
};
}
One simple way to do it is
Make sure you put/set the value this.state = {image: 'image-to-load.jpeg'} in render.
<img src={this.state.image} ref={image => this.image = image} onError={() => this.image.src = '/alternate-failover.jpg'
It worked for me. Small, precise, and reliable code
Ref: https://stackoverflow.com/a/42848501/10231115