'load' event listener for detect image is done loaded is not working in react - javascript

I try to console some message when image is fully loaded using 'load' listener, but the code did not work, how to properly write a 'load' event listener in react ? Thankyou
useEffect(() => {
window.addEventListener('load', (event) => {
const imageTest = document.querySelector('img')
const isLoaded = imageTest.complete && imageTest.naturalHeight !== 0
console.log(isLoaded)
})
}, [])

This is not how react works. You are trying to use load event within the component when everything else is already loaded within from <div id="root"></div>.
React is Single Page App. And for the whole document load happens once only :)
However for individual elements we can set onload and fire that event in componentDidMount() or in useEffect() Hook
UPDATE: For image load check you do something like. You can do this or even use useRef()
useEffect(() => {
const imageTest = document.querySelector('img');
imageTest.onload = ()=>{
// Image is loaded and your further steps :)
const isLoaded = imageTest.complete && imageTest.naturalHeight !== 0
console.log(isLoaded);
}
}, []);
There is also one more easy way to do this:
Using onLoad synthetic event right on the image element itself. Which I think should also work fine:
const ImageLoadDemo ()=> {
const handleImageLoaded =()=> {
console.log("Image was successfully loaded");
}
const handleImageErrored =()=> {
console.log("Image was not loaded successfully");
}
return (
<div>
<img
src="https://picsum.photos/200/300"
onLoad={handleImageLoaded}
onError={handleImageErrored}
/>
</div>
);
}

The way to listen image is successfully loaded in react component is just put onLoad on your <img> tag, for example :
const MyCompoent = () => {
return <img src="yourImageLink.png" onLoad={()=>{console.log('The Image is successfully loaded')} } />
}
instead console a message you can pass a function as well

Related

React js document event "readystatechange" not called

I recently changed my pc I was working with, uploaded all my code on github and cloned it back and something strange is happening, the readystatechange event of the document is not getting fired anymore.
I use React as my framework and I have this code that wait for the document to be ready to find the dimension in pixels of a flexbox div.
function useElementDimension(elementId: string) {
const [dimensions, setDimensions] = useState({
height: 0,
width: 0
});
useEffect(() => {
function onLoaded() {
if(document.readyState != "complete") return;
const stage = document.getElementById(elementId);
if(stage === null) return;
setDimensions({width: stage.clientWidth, height: stage.clientHeight});
}
document.addEventListener('readystatechange', onLoaded);
return (() => document.removeEventListener('readystatechange', onLoaded));
});
return dimensions;
}
It was working just fine in my other laptop, the effect is getting called and registering the event but the function onLoaded is never called.
Any idea?

Adding an Event Listener for Uploading a File that 'Fires' every time

I am trying to upload an excel file to my react app. I am using an event listener but it is only "picking up" the data the first time I upload a file. For example, I start my local server and then upload a file, test1.xlsx this works correctly. I then upload a second file, test2.xlsx. This also works. However, now if I try to upload either test1.xslx or test2.xlsx. Nothing will appear in the console. My code is as follows:
const input = document.getElementById('input-data')
if(input){
input.addEventListener('change', () => {
var data = [];
readXlsxFile(input.files[0]).then((rows) => {
data.push(rows)
})
console.log(data)
})
}
I am fairly new to all this so I am not sure if there is an event listener other than 'change' that would be better or if it is something to due with how the browser is storing the data. Let me know!
I've had success with this (only showing skeleton, but using this structure to load images):
<input onInput={onSelectFile} type="file" ... />
and
const onSelectFile = (e) => {
const onLoadFn = (dataURL) => {
// processing goes here, maybe something like
setImage(dataURL);
};
if (e.target.files && e.target.files.length > 0) {
const reader = new FileReader();
reader.addEventListener("load", () => onLoadFn(reader.result));
reader.readAsDataURL(e.target.files[0]);
// setState etc could go here, something like
setDialogOpen(true);
}
};

Loading JavaScript file and access it from ReactJS app

I'm trying to load a JavaScript file from a URL in my React application.
I'm using a <script> in the head of HTML of my project. I can see it loaded in the network of the console Chrome, and that's OK.
Now I'm trying to use a function from this file in my React application, with window.nameOfTheFunction, but I cannot access it.
How can I do that?
Using the window function is non ideal. How you do it depends on where the .js code is.
JavaScript on your server
If the JavaScript is located on your server then the best way to approach it is to bundle the JavaScript code with a bundler such as Webpack and then use the import function.
JavaScript on a remote server
If you want to use JavaScript from a remote server then you need to load the code and confirm it's loaded before using it. The reason is that some code may load slower from your source due to its size or network traffic and you don't want your code to break because of those reasons. The following code should help:
function App() {
const status = useScript(
'https://pm28k14qlj.codesandbox.io/test-external-script.js'
);
return (
<div>
<div>
Script status: <b>{status}</b>
</div>
{status === "ready" && (
<div>
Script function call response: <b>{TEST_SCRIPT.start()}</b>
</div>
)}
</div>
);
}
// Hook
function useScript(src) {
// Keep track of script status ("idle", "loading", "ready", "error")
const [status, setStatus] = React.useState(src ? "loading" : "idle");
React.useEffect(
() => {
// Allow falsy src value if waiting on other data needed for
// constructing the script URL passed to this hook.
if (!src) {
setStatus("idle");
return;
}
// Fetch existing script element by src
// It may have been added by another intance of this hook
let script = document.querySelector(`script[src="${src}"]`);
if (!script) {
// Create script
script = document.createElement("script");
script.src = src;
script.async = true;
script.setAttribute("data-status", "loading");
// Add script to document body
document.body.appendChild(script);
// Store status in attribute on script
// This can be read by other instances of this hook
const setAttributeFromEvent = (event) => {
script.setAttribute(
"data-status",
event.type === "load" ? "ready" : "error"
);
};
script.addEventListener("load", setAttributeFromEvent);
script.addEventListener("error", setAttributeFromEvent);
} else {
// Grab existing script status from attribute and set to state.
setStatus(script.getAttribute("data-status"));
}
// Script event handler to update status in state
// Note: Even if the script already exists we still need to add
// event handlers to update the state for *this* hook instance.
const setStateFromEvent = (event) => {
setStatus(event.type === "load" ? "ready" : "error");
};
// Add event listeners
script.addEventListener("load", setStateFromEvent);
script.addEventListener("error", setStateFromEvent);
// Remove event listeners on cleanup
return () => {
if (script) {
script.removeEventListener("load", setStateFromEvent);
script.removeEventListener("error", setStateFromEvent);
}
};
},
[src] // Only re-run effect if script src changes
);
return status;
}

Javascript - Fetch request happening after it supposed

I'm still new to javascript, I have this javascript problem from CS50 that is supposed to open a mailbox and clicking on an email is supposed to open the email. I think my on click part of the problem is right, but when I open my page and click on an email it doesnt call the open_mail() function.
I've solved that the problem is that the load_mailbox function for being asynchronous is beign called after the DOM finishes to load, so technically theres no div with the class email-box when the DOM finishes to load, but i don't know how to solve this problem, can someone help please.
document.addEventListener('DOMContentLoaded', function() {
// Use buttons to toggle between views
document.querySelector('#inbox').addEventListener('click', () => load_mailbox('inbox'));
document.querySelector('#sent').addEventListener('click', () => load_mailbox('sent'));
document.querySelector('#archived').addEventListener('click', () => load_mailbox('archive'));
document.querySelector('#compose').addEventListener('click', compose_email);
document.querySelector('#compose-form').addEventListener('submit', send_mail);
document.querySelectorAll('.email-box').forEach(function(box) {
box.addEventListener('click', function (){
open_mail();
})
});
// By default, load the inbox
load_mailbox('inbox');
});
function load_mailbox(mailbox) {
fetch(`/emails/${mailbox}`)
.then(response => response.json())
.then(emails => {
document.querySelector('#email-content').innerHTML = "";
emails.forEach(inbox_mail);
})
};
function inbox_mail(email) {
const element = document.createElement('div');
if (document.querySelector(`#email-${email.id}`) === null) {
element.id = (`email-${email.id}`);
element.className = ("email-box");
element.innerHTML = `<p>From ${email.sender}</p><p>${email.subject}</p><p>At ${email.timestamp}
</p>`;
document.querySelector('#email-content').append(element);
}
}
I´d say the easiest solution would be to put the addEventListener to a point after the elements with class .email-box are created, e.g in your .then function after inbox_mail ran for each email
.then(emails => {
document.querySelector('#email-content').innerHTML = "";
emails.forEach(inbox_mail);
document.querySelectorAll('.email-box').forEach(function(box) {
box.addEventListener('click', function (){
open_mail();
});
});
});
DOMContentLoaded will trigger when the DOM from the initial request/response was loaded. What you are doing in your fetch callback is called "DOM-Manipulation" as you create elements and append them to the DOM that has already been loaded.

Svelte component onLoad

Is there a way to know when a Svelte component has finished loading all its external resources, rather than onMount?
It is similar to the onload event of window.
EDIT: To clear things up, I would like a component to do something after it fully loads all its images.
EDIT2: I decided to use javascript to load images. In my opinion, this is not the cleanest way to do things, but it works.
Thank you!
EDIT2: I decided to use javascript to load images. In my opinion, this is not the cleanest way to do things, but it works. Thank you!
That's the way to go. Svelte doesn't try to wrap everything JS, but only what it can add real value to. Here JS is perfectly equipped to handle this need.
You can use a Svelte action to make it more easily reusable:
<script>
let waiting = 0
const notifyLoaded = () => {
console.log('loaded!')
}
const onload = el => {
waiting++
el.addEventListener('load', () => {
waiting--
if (waiting === 0) {
notifyLoaded()
}
})
}
</script>
<img use:onload src="https://place-hold.it/320x120" alt="placeholder" />
<img use:onload src="https://place-hold.it/120x320" alt="placeholder" />
If you need to reuse this across multiple components, you might want to wrap this pattern into a factory (REPL):
util.js
export const createLoadObserver = handler => {
let waiting = 0
const onload = el => {
waiting++
el.addEventListener('load', () => {
waiting--
if (waiting === 0) {
handler()
}
})
}
return onload
}
App.svelte
<script>
import { createLoadObserver } from './util.js'
const onload = createLoadObserver(() => {
console.log('loaded!!!')
})
</script>
<img use:onload src="https://place-hold.it/320x120" alt="placeholder" />
<img use:onload src="https://place-hold.it/120x320" alt="placeholder" />

Categories

Resources