How to add a priority to react components? - javascript

I want my Home component to load first and then everything else? How can I achieve this?
Or can I load resources in the background while I'm showing a spinner and then show the whole page? Something like this..
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 2500);
}, []);
return isLoading ? (
<Spinner />
) : (
<div className="App">WholePage</div>

What I would do is use the useEffect hook for the priority component that you want to load first and set a state in there to load the remaining components.
My code would look something like this:
function App(){
const [homeLoaded,setHomeLoaded] = useState(false)
const getHomeLoaded = (homeLoaded) => {
setHomeLoaded(homeLoaded)
}
return(
<>
<Home gethomeLoaded = {getHomeLoaded}/>
{homeLoaded ? <OtherComponents>:null}
</>
)
}
The home component would look something like this:
function Home(){
useEffect(() => {
props.getHomeLoaded(true)
}, []);
return(
<div>Your home content goes here</div>
)
}
What I am essentially doing is passing a state to the parent component from Home so that I can set homeLoaded to true only after Home component is loaded

Related

In react, how to display component only after all data is available?

I have a component that displays images. The component has a menu bar as well.
During initially server request, this component always shows the menu bar for a split second because the actually image is not loaded yet.
How to display the menu bar only after the image is ready?
EDITED:
I can determine when the URLs to the images are loaded and available. But how to tell if the actually image itself is ready?
You can do it like this:
function YourComponent () {
const [imgLoaded, setImgLoaded] = useState(false);
const handleImgLoad = () => {
setImgLoaded(true);
}
return(
<>
<img onLoad={handleImgLoad} src="..." alt="..." />
{imgLoaded ? <MenuBar /> : <></>}
</>
);
}
You can use partial rendering
for example
import React, { useEffect, useState } from 'react';
function App() {
const [data, setData] = useState(null);
useEffect(()=>{
setData(true);
}, []);
return (
<div>
{data && <div> after data is not null this will be visible</div>}
</div>
);
}
export default App;
You can set a state as below and load the menu based on this value;
const [ImageLoaded, setImageLoaded] = useState(false);
You can have a loading state set to true by default, this way:
const [loading, setLoading] = useState(true);
After you have all your data fetched, you set it to false:
setLoading(false)
And your render will be something like this:
return (
<div>
{loading ? <p>loading...</p> : <MyComponent/>}
</div>
)

Way to render a new component onClick in react js

Am trying to render a new component onclick a button in react js. Am using functional components and I can't handle it. Eg: am in the UserManagement component and on a button click I need to render another component named employee management.
You can conditionally render your component.
Example :
EmployeeManagement.js
const EmployeeManagement = () => {
....
return (
<div>
EmployeeManagement
</div>
);
}
UserManagement.js
const UserManagement = () => {
const [hasRender, setRender] = useState(false);
const onShow = React.useCallback(() => setRender(true), []);
return (
<>
<button onClick={onShow}>Show Employee Management</button>
{hasRender && <EmployeeManagement />}
</>
)
}
One way to do this would be to add a local state in UserManagement,
that holds a boolean value indication whether the component should be hidden or shown.
Then you will have something like:
function UserManagement() {
const [compIsShown, setCompIsShown] = useState(false);
return (
// Whatever else you're rendering.
<button onClick={() => setCompIsShown(true)}>...</button>
{compIsShown && <OtherComp />}
)
}
What will happen is that compIsShown will initialize as false,
so this condition compIsShown && <OtherComp /> will prevent it from rendering.
Then, when you click the button, the state will set, causing a re-render, except now the condition will be true, so <OtherComp> will be rendered.
There are other ways to go about this.
Depends mostly on the use-case.
use a visible state & toggle it in onClick:
const [visible, setVisible] = useState(false)
onClick = () => {setVisible(true)}
then render it like this:
{visible && <EmployeeManagement onClick={onClick} />}

Bug with React: component not rendering until page is refreshed

I have this carousel component that I'm calling from a page but it's not showing until I refresh the page. If I have the Box component and switch to the Carousel component it doesn't work until I refresh the page but if I render the Carousel component first, render Box then go back to Carousel it works. Is this a bug with ReactDOM or what?
My carousel component:
const Carousel = () => {
const { carousel, setCarousel } = useContext(AppContext);
useEffect(() => {
setCarousel(true);
return () => {
setCarousel(false);
};
}, [carousel]);
const items = ["image1.svg", "image2.svg", "image1.svg", "image2.svg"];
const responsive = {
0: { items: 1 },
1024: { items: 2 },
};
return (
<div
className={`container flex`}
style={{
marginTop: "40px",
}}>
<AliceCarousel
disableDotsControls
disableButtonsControls
autoHeight={true}
autoWidth={true}
responsive={responsive}
animationType='slide'>
{items.map((i, index) => (
<img src={i} key={index} alt='' srcSet='' className={Styles.slider} />
))}
</AliceCarousel>
</div>
);
};
And I'm switching/calling it on another component like this:
const { carousel, modalIsOpen, openModal, closeModal } = useContext(
AppContext
);
return (
<div className={carousel ? Styles.layout : ""}>
<div>
<Box />
</div>
</div>
)
I need to make the component re-render when it's called or something so that it works properly, even when I call the AliceCarousel component on my page directly I still have this issue.
Is this something to do with React or the component itself? Thanks
Your useEffect logic leads to infinity loop as after changing the state to true, by having the state in dep array [carousel], you changing it back to false from the cleanup function.
// Useless useEffect, always false.
useEffect(() => {
setCarousel(true);
return () => {
setCarousel(false);
};
}, [carousel]);
See When does the useEffect's callback's return statement execute?

How to display toast using react-toastify inside class component when props check is true

I am working on react project where i am trying to display toast using react-toastify , inside a div section when props ( isNotificationOpen ) is true. I tried an example something like bellow but i dont want the toast be triggered when button press occurs , i want the the tost to be triggered when isNotificationOpen props is set to true , how can i achieve this?
const notify = () => toast("Wow so easy !");
render() {
return (
<div className="d-flex" style={{ margin: "25px" }}>
<div className="mr-auto p-2">
{this.props.isNotificationOpen ? (
<div>
<div>
<button onClick={notify}>Notify !</button>
<ToastContainer />
</div>
//Show toast here...
</div>
) : (
<p />
)} ```
Use a component lifecycle function to respond to the isNotificationOpen prop changing to trigger a notfication.
Class-based component example
notify = () => toast('Wow so easy!');
componentDidMount() {
const { isNotificationOpen } = this.props;
isNotificationOpen && this.notify();
}
componentDidUpdate(prevProps) {
const { isNotificationOpen } = this.props;
if (prevProps.isNotificationOpen !== isNotificationOpen) {
isNotificationOpen && this.notify();
}
}
Functional component example
useEffect(() => {
props.isNotificationOpen && toast('Wow so easy!');
}, [props.isNotificationOpen]);

How do you push a UI update to a javascript frontend?

So I'm building a simple react app that fetches a bunch of images and displays them as cards.
The intention is to show an info message until all the images have loaded, then removing the notice again.
const App = () => {
const [cardInfo, setCardInfo] = useContext(CardInfoContext)
useEffect(() => {
fetchData(setCardInfo)
}, [])
useEffect(() => {
const app = document.querySelector('.app')
for(const child of app.children){
app.removeChild(child)
}
const loadingNotice = document.createElement('h1')
loadingNotice.innerHTML = "Fetching data ..."
app.appendChild(loadingNotice) //<-- this never shows up
cardInfo.forEach( info => {
const img = document.createElement('img')
img.src = info.image
app.appendChild(img)
})
app.removeChild(loadingNotice)
}, [cardInfo])
return (
<>
<div className="app">
<h1>Fetching data...</h1>
</div>
</>
)};
What instead happens is the app stays blank until all the images are loaded, then shows all the images at once -- but never the loading notice.
Can I somehow "push" the loading indicator change to the UI independent of the rest of the rendering?
Another thing I tried was
const App = () => {
const [cardInfo, setCardInfo] = useContext(CardInfoContext)
useEffect(() => {
fetchData(setCardInfo)
}, [])
useEffect(() => {
const app = document.querySelector('.app')
if(!cardInfo) return
const loadingNotice = app.querySelector(".loadingNotice")
loadingNotice.style.display = 'block' //<-- this never shows up
cardInfo.forEach( info => {
const img = document.createElement('img')
img.src = info.image
app.appendChild(img)
})
loadingNotice.style.display = 'none'
}, [cardInfo])
return (
<>
<div className="app">
<h1 className="loadingNotice">Fetching data...</h1>
</div>
</>
)}
Which would be incorrect because I do need to remove all the images, at least, but even that only displayed the loading notice for a fraction of a second, then the component goes blank until all the images can be displayed.
useEffect observes when cardInfo is changed, not when the render the comes after fired. You can use useLayoutEffect instead.
...but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.
BTW, I wouldn't combine direct DOM manipulation with React to avoid issues like this (among other reasons)
Something like
const App = () => {
const [isLoadgin, setIsLoading] = useState(true)
const [cardInfo, setCardInfo] = useContext(CardInfoContext)
useEffect(() => {
fetchData(result => {
setCardInfo(result);
setIsLoading(false);
})
}, [])
return (
<>
<div className="app">
{isLoading && <h1 className="loadingNotice">Fetching data...</h1>}
{
cardInfo.map(card => <img src={card.image} />)
}
</div>
</>
)}
You need conditional rendering instead of all that DOM manipulation you are trying in the useEffect.
...
return(
<>
<div className="app">
{ !cardInfo ? <h1 className="loadingNotice">Fetching data...</h1> : <Cards info={cardInfo} /> }
</div>
</>
)
Note: I am assuming you have something like <Cards> component that displays cards details.

Categories