React lazy load expensive material-ui modal - reactjs

I have got expensive material-ui modal component that takes around 1s to render which I tried to lazy load with Suspense and React.lazy but it didn't work for me, if I understand it correctly it only lazy loads import (?)
About the modal component, there is no fetching from api or anything just many components with hooks and material-ui inside and data passed as props
The process that I have now:
I click button
1s passes
everything is loaded and modal opens
What I'm trying to accomplish"
I click button
Modal immediately pops up and shows some sort of loading screen
When component is ready it shows up
how can I do it in react?

You can apply a simple check in your modal component and render it conditionally. So suppose if your have three data the you can use ternary operator just below the return the data only if all data is loaded and if not then show a loading component
Sample code might make you clear what I'm trying to say. In my case the data was coming from an API so I put a check if that data is loaded or not.
function ModalComponent(data1, data2, data3){
/////// other code //////
return (
<div>
{data1 && data2 && data3 ? (
<div>Your data </div>
) : <div>Loading....</div>
}
</div>)
}
export default ModalComponent

Related

How can I tell if an React-Bootstrap component has finished rendering?

I have a React Bootstrap accordion with a lot of data in it that takes a couple seconds to load and doesn't work properly if you try to expand it before that. I would like to hide/overlay the accordion until the render is finished.
To be clear: this is not a question of waiting on the server for the data to load - it's all available on the client, there's just a lot to render. I can't find anything in the React docs about how to handle this case.
I tried using Accordion onLoad event to set a loading flag in component state. However, Bootstrap never seems to actually trigger it and I can't find any other event that I would expect to work.
Update: I am using functional components by the way.
Ok I figured it out, set the loading flag in an empty-array useEffect for the component and it'll trigger when the rendering is complete. Very simple solution, just not as immediately intuitive with functional components.
const [accordionRendering, setAccordionRendering] = React.useState(true);
...
React.useEffect(() => setAccordionRendering(false), [])
...
return <React.Fragment>
<Spinner animation="border" className={accordionRendering ? '' : 'd-none'}/>
<Accordion activeKey={activeKey} onSelect={onAccordionChanged} className={accordionRendering ? 'invisible' : ''}>
...

Modal start and exit animation logic inside a single React component

I have been trying to solve this problem for a very long time. I will be very glad for your help.
I have 3 functional components.
export const HomePage = () => {
const [menu,setMenu]=useState(false)
return (
<>
<Header menuState={()=>setMenu(!menu)} />
{menu&&<Menu/>}
</>
)
}
function Header(props){
return(
<div className='Header'>
<div className='button' onClick={()=>props.menuState()}/>
</div>
)
}
function Menu(props){
function animateExit() {
console.log("I'm trying to call this function from the Header component")
}
useEffect(() => {
function animateStart() {
console.log('Animation works! :)')
}
return()=>{console.log("In this case, the animation will not have time to appear, as the component will be instantly removed")}
},[]);
return(
<div className='Menu'/>
)
}
By clicking the button in the Header component, I am adding a Menu component to the home page. So I open the menu.
For smooth opening, I use an animation function, for example, I'll call it AnimateStart. It's in the "Menu" component in UseEffect .
To exit the menu, press the same button again.
I really want to put AnimateExit in the menu component. So all the logic of a component is inside that component.
For this you need either:
How to call this function from header component
Catch the removal of the component through the return of useEffect, but the function in the return must work until the removal. I don't know if this is possible.
At the moment, I'm writing exit animation logic in the Header component. It is not comfortable. I want to put all menu animation in Menu .
I hope you understand what I mean.
I would be glad for any advice on how to make a self-sufficient component, and not scatter its code into different blocks.
Thank you!
From what I was able to understand, you are currently facing problems with making the exit animation work because the Menu disappears quickly after clicking on the button in the Header component.
That is because your code mentions it clearly that show the Menu component only when menu variable is set to true. Which means your exit animation will not have time to be processed. The way you could handle this is by using CSS classes that have animation effect on them and you can switch between these classes based on the boolean value in your menu variable.
Refer to this example: CSS based animations
Also: Visibility with animation
I'd appreciate it if you could accept the answer if it helps your case!

React Context always returns EMPTY

I have a Search parent component and a SideBar child component, I am trying to get context in SideBar, but everytime it returns empty.
I followed the tutorial exactly like: https://itnext.io/manage-react-state-without-redux-a1d03403d360
but it never worked, anyone know what I did wrong?
Here is the codesandbox link to the project: https://codesandbox.io/s/vigilant-elion-3li7v
I wrote that article.
To solve your specific problem:
When using the HOC withStore you're injecting the prop store into the wrapped component: <WrappedComponent store={context}.
The value of the prop store is an object that contains 3 functions: get, set, and remove.
So, instead of printing it, you should use it. For example this.props.store.get("currentAlbums") or this.props.store.set("currentAlbums", [album1, album2]).
This example is forked by your code: https://codesandbox.io/s/nameless-wood-ycps6
However
Don't rewrite the article code, but use the library: https://www.npmjs.com/package/#spyna/react-store which is already packed, tested, and has more features.
An event better solution is to use this library: https://www.npmjs.com/package/react-context-hook. That is the new version of the one in that article.
This is an example of a sidebar that updates another component content: https://codesandbox.io/s/react-context-hook-sidebar-xxwkm
Be careful when using react context API
Using the React Context API to manage the global state of an application has some performance issues, because each time the context changes, every child component is updated.
So, I don't recommend using it for large projects.
The library https://www.npmjs.com/package/#spyna/react-store has this issue.
The library https://www.npmjs.com/package/react-context-hook does not.
You pass the store as a prop, so to access it, you need this.props.store in your SideBar.
Not this.state.store
Create a wrapping App component around Search and Sidebar:
const App = props => (
<div>
<Search />
<SideBar />
</div>
);
export default createStore(App);
Now you can manipulate state with set and get that you have available in child components Search and Sidebar.
In Search component you can have something like:
componentDidMount() {
this.props.store.set("showModal", this.state.showModal);
}
also wrapped with withStore(Search) ofc.
and in SideBar you can now call:
render() {
return (
<div>
{"Sidebar: this.state.store: ---> " +
JSON.stringify(this.props.store.get("showModal"))}
}
</div>
);
}
and you will get the output.

Show warning on leaving without saving

I'm working on a React page which has a card component which opens on clicking a button. I'm trying to show a warning if the user tries to close the card without saving the changes. The card doesn't have a close button, it closes when clicking anywhere on the screen outside of the card.
I've built a similar warning modal by checking if the route has changed, however since in this case the card component is part of the same page I cannot apply the same logic.
<CardSidebar
onHide={(e) => this.setState({ showSidebar: false})}
>
<FormComponent
data={this.state.item}
filterTypes={this.state.filterTypes}
dataFields={stores.dataFieldStore.dataFieldsForDropDownComponents}
refresh={this.refreshListHandler}
cancelHandler={this.cancelHandler}
/>
<>
<RouteLeavingGuard
// when={?}
/>
</>
</CardSidebar>
So basically you want to know when the form is dirty and data is not saved so the guard would pop up. As far as I can see you are not using any library for handling this kind of behavior in forms so you need to build custom. I also don't see that you are using something as Redux so you need to lift state up and keep the isDirty value in the state of the component that is shown in the snippet.
//This code goes in the snippet that you pasted
state={
isDirty:false
}
isDirtyHandler(value){
this.setState({isDirty:value})
}
Pass the isDirtyHandler and isDirty as prop for check into the <FormComponent/> and inside the component make the following check
//This goes in <FormComponent/>
componentDidUpdate(prevProps, prevState) {
if(this.state.data !== prevState.data && !this.props.isDirty) {
this.props.isDirtyHandler(true)
}
onSubmitHandler(){
this.props.isDirtyHandler(false)
//whole logic for submitting the form
}
and just in the guard you are checking if form is dirty
<RouteLeavingGuard
popUp={isDirty}
/>

How to re-render a parent from a children component with hook?

I would like to force my parent to re-render the page when I click on a button from a child component.
(I don't use redux because I don't have the time to learn it in my project, so I use localStorage. Unfortunately React don't see when a change is operated on local Storage, so he don't re-render. It's why I would like to force it to re-render my page (to have the right content).)
I tried to use hook with the function useState to do it but it's not working and I don't know why...
(Nothing change in my page)
This is my parent page: (just the code important)
const[reload, setReload] = useState(false);
...
else if (user) { contents = [<Message_UserIdentified user={user} callBack={setReload}/>, contentform]; }
This is my child component:
const Message_UserIdentified = (props) => {
let user = props.user;
return (
<Alert color="primary" className="alert alert-dismissible alert-info">
<h4>Welcome {!user ? "" : user.firstname} {!user ? "" : user.lastname}</h4>
If you are not {!user ? "" : user.firstname} click <a onClick={() => {localStorage.removeItem('idUser'); props.callBack(true);}}>here.</a>
</Alert>
);
}
Why my parent page don't want re-render ?
Thanks in advance.
I have created a proof of concept of what you are trying to achieve and it works:
https://codesandbox.io/s/weathered-smoke-ojr5j
probably there's something else in your code that we can't see that's preventing the component to re render
Your child component can have a prop which directly pass setReload to it.
However one common usage is that, setReload can be associated with an event, ex. onReload. You can pass a prop onReload to the child instead.
<Child onReload={() => { setReload() }} />
Inside onReload implementation, you can call setReload.
The reload state variable in your parent component is strictly local to it; the child can't see it.
I've been using React Hooks for about 2 months now. The learning curve, at times, has been steep but I'm now getting really proficient at it.
A companion technology to Hooks called Context API is perfect for your needs. It's what you should be using rather than local storage because both components can access it. Your child component would set the equivalent of reload in the Context to true and your parent would have a useEffect function that would have reload as a dependency. Thus, when reload is changed from false to true, the useEffect function in the parent would be fired and run the code you desire.
Early on, I very much benefitted from this video series: https://www.youtube.com/watch?v=6RhOzQciVwI&t=46s Watch the first few videos and you should quickly understand how to implement the Context API in your functional React components.

Resources