React Promise - confusion in coding - reactjs

I am new to react, and trying to follow a tutorial of Promises. I merged the two files into one as below for convenience. However, I am totally lost as to how to display the desired images. I copied the last bit from another react application.
import React from 'react'
function DemoPromise2() {
function loadImage(url) {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = function () {
resolve(image);
};
image.onerror = function () {
let message = "Could not load image at " + url;
reject(new Error(message));
};
image.src = url;
});
}
// export default loadImage;
let addImg = (src) => {
let imgElement = document.createElement("img");
imgElement.src = src;
document.body.appendChild(imgElement);
};
Promise.all([
loadImage("images/img1.jpg"),
loadImage("images/img2.jpg"),
loadImage("images/img3.jpg"),
loadImage("images/img4.jpg"),
])
.then((images) => {
images.forEach((img) => addImg(img.src));
})
.catch((error) => {
// handle error later
});
return (
<div className="App">
Demo Promise2 -
<br />
???? Question :: how can I display images here??
</div>
);
}
export default DemoPromise2;

#Evert is correct, you need to load this into state to show the images.
TL;DR: Click Run code snippet below to see the code in action.
--
Longer Explanation:
useState will allow the data to be accessed with the component and allow it to be persisted within it. You either get the value with it's name or setValue to update it.
Ex:
const [myvalue, setMyvalue] = useState('defaultValue');
useEffect is use as another React but specifically for when state get modified and given that you give specific things to look for (or watch as an array)
Example Nothing To Watch:
useEffect(() => {
console.log('CODE IS RUN ONLY ONCE, Nothing to watch except when component loads');
}, []);
Example State To Watch:
const [value, setValue] = useState('watch this');
useEffect(() => {
console.log('RUN EACH TIME value is updated including first time set');
}, [value]);
Code:
// main.js
// for your code use: import React, { useState, useEffect } from 'react';
const { useState, useEffect } = React;
const App = () => {
// State / Props
const [images, setImages] = useState([]);
// Load Images Function
const loadImage = (url) => {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = () => {
resolve(image);
};
image.onerror = () => {
let message = `Could not load ${url}`;
reject(new Error(message));
};
image.src = url;
});
};
// Hook to use when the component is loaded and ready
// Equivalent to something like window.onload
useEffect(() => {
Promise.all([
loadImage('https://picsum.photos/seed/picsum/200/200'),
loadImage('https://picsum.photos/200/200')
])
.then((data) => {
setImages(data);
})
.catch((error) => console.log('ERROR', error));
}, []);
return <div><h1>My Images</h1><p>Images Loaded: {images.length}</p>{images.map((img, index) => <img key={`img-${index}`} src={img.getAttribute('src')} />)}</div>;
};
ReactDOM.render(<App />, document.querySelector('#root'));
<body>
<div id="root"></div>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script type="text/babel" src="main.js"></script>
</body>
====== CLARIFICATIONS ======
Question:
const [images, setImages] = useState([]); ???????????? the above defines const 'images'. Where is 'images' value modified? where is it receiving values/images?
Answer:
Think of this part as destructuring from a variable that's an array, but you're getting the getter and setter from useState.
The same way you would destructure an array like:
const myArray = [1, 2];
const [firstValue, secondValue] = myArray;
// firstValue = 1
// secondValue = 2
But instead of just plain values, you're getting the equivalent of functions returned to get the value and set a new value.
Note that useState is defined by React.
With that in mind, images is updated (set) here:
.then((data) => {
setImages(data);
})
Question:
2. let image = new Image(); ???????? whats the purpose of this sttmt? 'let image = new image()' ??? such was used to set an instance of a class but why is it used for a function? ????????
Answer:
new Image() is a base function baked into the browser, and would be typically be used for creating a new <img> with some event handling, or potentially other custom functionality.
Technically you do not need to use new Image() here if you're just going to rely on the browser to load the images naturally.
In the case of your initial code, the functionality exists to do something when the image is done loading, or handle errors in a specific way, but there isn't really any code except for resolving a promise.
What you would do is something like:
image.onload = () => {
// Images is loaded send message to custom logging software
// OR Image is loaded which works like a tracking pixel sent a message
// OR Image is loaded, append it to DOM and perform a fade in animation
resolve(image);
};
Sometimes you would just use this function to handle ordering images in a sequential way, or control the sequence of loading and animations.
On in the case of your code, wait until all the images are loaded, then show the page vs. loading them one by one natively in the browser.
Question:
3. image.onload = () => {resolve(image); 'image.onload' is just a const , will it hold the 'image'?
Answer:
It does not hold the image, this is just an event function that is defined by Image to handle when the image is done loading. So it's a predefined function that is called by Image, but defined by you.
Question:
?4. image.src = url .. ??
Answer:
This is the part of Image that starts the whole process, that's why it's defined at the end.
The code is saying.
// Before you begin you're going to be getting an image
let image = new Image();
// Before we load the image, I want to tell you how to handle it once
// it loads successfully
image.onload = function {
// custom instructions
};
// Before we load the image, I want to tell you how to handle it
// in case things go wrong
image.onerror = function {
// custom instructions
}
// Ok, we're good to go, start the process, here's the url
image.src = url; // https://picsum.photos/seed/picsum/200/200

Related

React Google Analytics Pageview showing without any code

I've implemented google analytics into a react app. The problem is that it just shows the page title upon every page view. What's really strange is that when I disable the code to update upon page change, it still registers each url change as a new pageview in Google Analytics (With the same page title as always). This is navigating to pages using the react-router-dom, not hard refreshed, but the pageviews are still showing in GA!
Here's the code I'm using
import { useLocation } from "react-router-dom";
import { useEffect, useState, createContext } from "react";
export const GoogleAnalyticsContext = createContext(null);
function GoogleAnalyticsProvider({children}) {
const [gaInitialized, setGaInitialized] = useState(false);
const [gaTrackingCode, setGaTrackingCode] = useState();
const location = useLocation();
useEffect(() => {
//Fetch tracking code
setGaTrackingCode('[my tracking code]')
}, [])
useEffect(() => {
if (gaTrackingCode) {
console.log("Updating script");
const script1 = document.createElement('script');
script1.async = true;
script1.src = `https://www.googletagmanager.com/gtag/js?id=${gaTrackingCode}`
document.body.appendChild(script1);
const script2 = document.createElement('script');
script2.async = true;
script2.text = `
window.dataLayer = window.dataLayer || [];
function gtag(){window.dataLayer.push(arguments);}
window.gtag = gtag;
gtag('js', new Date());
gtag('config', '${gaTrackingCode}', {
cookie_flags: 'SameSite=None;Secure'
});
`
document.body.appendChild(script2);
setGaInitialized(true);
}
}, [gaTrackingCode])
// useEffect(() => {
// if (gaInitialized) {
// window.gtag('config', gaTrackingCode, {
// page_title: location.pathname + location.search,
// page_page: location.pathname + location.search
// })
// }
// }, [gaInitialized, location])
const store = {
gaInitialized
}
return <GoogleAnalyticsContext.Provider value={store}>{children}</GoogleAnalyticsContext.Provider>
}
export default GoogleAnalyticsProvider
Notice the commented out part. It's still registering new pageviews even with that commented out.
I'd wonder if Google has implemented some new feature, if it weren't for the fact that I've got the exact same setup running in a different environment, and this doesn't happen, and the pageviews work correctly (with the commented out code uncommented)
Edit: I've checked with console.log, and the initialization script is only being called once.
Edit2: I'm using a workaround. I can send events successfully, so I'm sending all the pageviews as events.

Is there any way to sort out the problem of delay or (lag) in rendering? in reactjs

Actually, I made a drag and drop component in my application. And the problem I faced is when I drop a picture in that component, it doesn't render on the screen. But on next go it render the picture that I uploaded last time and vice versa.
<div className="uf-upload-box" style={{"text-align":"center", "padding-top":"30px"}}
onDrop={onChangeHandler}>
const onChangeHandler = (event) => {
console.log("Hello");
setIsLoading(true);
let reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.addEventListener("load", () => {
fabric.Image.fromURL(reader.result, function (img) {
setIsLoading(false);
console.log(img);
activeCanvas.add(img);
});
});
}
It would be great if you could share more of your code. For example, how you are managing the component state?
However, this problem indicates the UI is getting updated via setIsLoading(false) before the image is actually added to activeCanvas.
Now what is activeCanvas? If it is an array of images, you can do something like this:
const [activeCanvas , setActiveCanvas] = useState([]);
And as the image is loaded successfully:
reader.addEventListener("load", () => {
fabric.Image.fromURL(reader.result, function (img) {
setIsLoading(false);
setActiveCanvas([...activeCanvas , img]);
});
});
I sorted out the issue that I faced, what I did is; just change the event on dropping the file from ondrop to onChange. And I got the desired result.
replace this one:
onDrop={onChangeHandler}
from this one:
onChange={onChangeHandler}

Playing audio with useEffect hook on page load

I am building a tribute page and I want to have my audio play when the page loads, every time.
So far it seems to play only sometimes and I'm not sure why.
var audio = new Audio("theme.mp3");
const Playit = () => {
audio.play();
}
useEffect(() => Playit(), [Playit]);
I am sure that I am using the useEffect hook improperly because I am trying to make it work like componentDidMount
How would I get the audio to play whenever the page loads?
Thank you in advance.
So it turns out you can't have an autoplaying audio on chrome. Chrome blocks it. You can however have audio controls like so
const [audio, SetAudio] = useState("");
const Playit = () => {
audio.play();
};
const Stopit = () => {
audio.pause();
};
useEffect(() => {
SetAudio(new Audio("theme.mp3"));
}, []);
var audio = new Audio("theme.mp3");
const Playit = () => {
audio.play();
}
useEffect(() => Playit(), []);
Create the audio object inside Playit function. Also pass an empty array as the second argument in the useEffect hook.
const Playit = () => {
var audio = new Audio("theme.mp3");
audio.play();
}
useEffect(() => {Playit()}, []);
sorry i cant add a comment.
It seems that when running the Playit(), theme.mp3 is not ready for play.Does it not play every time when the page is refreshed

Loading mxgraph in react useEffect method problem

I try to show a mxgraph object after I upload a file to a server. The server runs ANTLR and returns the parsed data as JSON Object. I use Typescript to generate an Object out of my JSON result. This Object is set to a variable with react useState.
Now my problem:
after I set the diagram variable with useState, the useEffect is fired up. In the useEffect my goal is to show the mxgraph. The Graph is shown, but it creates a new component every time the useEffect is Called and the graph appears in a new div
My question is, is there a way crating the graph in the useEffect method and only showing it in the intended div?
Component Header
const [diagram, setDiagram] = useState<IDiagram>();
const divGraph = React.useRef<HTMLDivElement>(null);
The api call
const onSubmit = async (e: any) => {
e.preventDefault();
const formData = new FormData();
formData.append("file", file);
try {
const res = await axios.post("/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
//create a TypeScript Object out of result
var diag = diagramCreator.createDiagram(res.data);
//sets the diagram variable with useState
setDiagram(diag);
} catch (err) {
console.log(err);
}
};
The useEffect
useEffect(() => {
if (!mxClient.isBrowserSupported()) {
mxUtils.error("Browser is not supported!", 200, false);
}
else {
const graph = new mxGraph(divGraph.current);
graph.setConnectable(true);
graph.setHtmlLabels(true);
mxEvent.disableContextMenu(divGraph.current);
if(typeof diagram !== 'undefined' ){
var mxGraphCreator = new MxGraphCreator(graph,diagram);
graph.getModel().beginUpdate();
mxGraphCreator.start();
graph.getModel().endUpdate();
}
}
});
the 'HTML' part
return(
<Fragment>
...
<div
className="graph-container"
ref={divGraph}
id="divGraph">
</div>
</Fragment>
);
here you see the actual result:
my goal is to show the orange diagram in the top
turquoise area
If you need more information please ask. Thanks

Value of state variable is lost - React

I want to build a CRUD in React with Laravel and Firebase. Everything is perfect when I'm working with text, but I got trouble when I try to upload an image to Firebase Storage. I can save it but I can't get its URL.
I wrote 2 "console.log". In the first one the URL is there, but the second one (when I try to get the URL from the state variable) doesn't return anything.
handleSubmit = event =>{
event.preventDefault();
const {imagen} = this.state;
if(imagen!=null){
const uploadTask = storage.ref(`imagenes/${imagen.name}`).put(imagen);
uploadTask.on('state_changed',
(snapshot) => {
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
this.setState({progress});
},
(error) => {
console.log(error);
},
() => {
storage.ref('imagenes').child(imagen.name).getDownloadURL().then(url => {
this.setState({url});
console.log(this.state.url); //<<<<<<<<<<<<<SHOW URL (IT'S OK!)
})
});
}
var direccion = null;
const form = event.target;
let data = new FormData(form);
data.append('url', this.state.url);
console.log(this.state.url); //<<<<<<<DOESN'T SHOW URL !! (HERE'S THE TROUBLE)
If you want to check the entire file:
https://github.com/AndresVasquezPUCE/project/blob/master/pelicula
I'm not a professional, so please don't be rude :D
this.setState is asynchronous
If you want to get the updated state value, add a callback and access the new state there like
this.setState({ url: 'some url'}, () => {
conosle.log(this.state.url);
});
Data is loaded from Firebase asynchronously. By the time your console.log(this.state.url); //<<<<<<<DOESN'T SHOW URL !! (HERE'S THE TROUBLE) the data hasn't been loaded from Firebase yet, and the then hasn't been called yet.
Any code that needs the data from Firebase needs to either be inside the then() callback (such as console.log(this.state.url); //<<<<<<<<<<<<<SHOW URL (IT'S OK!)) or be called from there (such as this.setState({url})).

Resources