React.js onShow event handler - javascript

I have a tabbed menu on my page, which is basically a bunch of divs that get shown/hidden depending on the tab that's clicked. I want to be able to refetch the data in a React Component in one of the divs once it appears.
componentDidMount fires at the very beginning, so it's not an option. It would be nice to just have an HTML event onShow similar to onClick but nothing like that seems to exist.
Any suggestions?

I have a Tabs component but in my case, all tabs content are mounted but not displayed. When I click on a tab, I just change the visibility with css
But to refetch data, you should make a component for the containers that fetch the data in his componentDidMount so, in the top level if you switch which one renders, the componentDidMount will trigger.
Put some code if you want some help with your case

Per the docs, componentDidUpdate is probably what you're looking for. It's called after props and/or state has changed and the component has re-rendered (not called for the initial render).
That said, it's probably simpler to just handle the data fetching in the onClick handler itself or better yet, fetch the data once in the parent component and pass down the relevant slice of data to the tabs and then show / hide as appropriate.

Hey You have to separate out the tab as component and render those component based on tab changed let me give one example over here.
Suppose I have one Page called MainPage in that Page I have Tab Control which Contain the Three tab First,Second and Third.
first you have to create a three Component like
var First=React.createClass({ // First Tab Content goes here });
var Second=React.createClass({// Second Tab Content goes here});
var Second=React.createClass({// Third Tab Content goes here});
Now your MainPage Should look like
var MainPage=React.createClass({
onClick:function(e)
{
if($(e.target).attr('id')=="1")
{
React.render(<First />,document.getElementById('tab-content'));
}
else if($(e.target).attr('id')=="2")
{
React.render(<Second />,document.getElementById('tab-content'));
}
if($(e.target).attr('id')=="3")
{
React.render(<Third />,document.getElementById('tab-content'));
}
},
render:function()
{
return(
<div>
<div>
//Three Tabl goes here
<div id="1" onClick={this.HandleTab}>Tab 1</div>
<div id="2" onClick={this.HandleTab}> Tab 2</div>
<div id="3" onClick={this.HandleTab}>Tab 3</div>
</div>
//your Container Div
<div id="tab-content">
</div>
</div>
)
}
})

Related

How to send data from v-for to event handler in Vue?

I am having problems with sending the right data to the event handler of a subcomponent in my Vue component.
Here is my code:
<template>
<div>
<div v-for="item in [1, 2, 3]">
<div #click=test(item)>test</div>
<ConfirmModal v-if="showModal" #confirmed=test(item) />
<button v-on:click="showModal = true" ></button>
</div>
</div>
</template>
<script>
import ConfirmModal from 'ConfirmModal'
export default
{
components: {ConfirmModal},
data()
{
return {showModal: false}
},
methods:
{
test(item)
{
console.log(item);
this.showModal = false;
},
},
}
</script>
And here is the code for a subcomponent:
<template><div class="modal" #click.self="$emit('confirmed')">subtest</div></template>
So, basically, I here have an array of numbers and am using the v-for to iterate over an array.
For each item one test label, one subcomponent (containing a subtest label) and one button is created. When button is clicked, subcomponent is shown. When I click on the subcomponent (subtest label) it disappears.
div is a standard component which emmits #click events when it is clicked upon.
confirmModal is a very simple component which listens for #click events and redirects them into #confirmed events.
So, this code generates 3 times 3 items. When I click on any of the labels, test method is called which logs the value of the item.
When I click on any of the test labels, I get the correct value in the console, that is, 1 for the first item, 2 for the second item and so on.
But, when I click on any of the subtest labels, I allways get the 3, whichever link I clicked. (If I change the order of items in the array, then I allways get whichever item I put on the last place in the array).
I do not understand what is going on here, it is the same method called on the same way. Why is 3 allways logged in console when I click on the subtest label?
If you wonder what is class=modal in my subcomponent used for, I have no idea. This is a skeleton of two components in a very complex project consisting of thousands of files built on top of the Liferay, and there are more then ten files where is .modal defined in many directories. So I am not sure from which file does this particular component load this class. I did not throw it out of this skeleton code just because when I remove this class from the div in the subcomponent, everything works fine. I have no idea why. How can a class stop the correct data from being received? I do not get this.
I know that this bug may not be reproducable, because I did not provide the definition of the .modal style, but I posted it anyway, because I hope that you can see something else in the code what is wrong or propose another way how to execute the test method on #confirmed event.
I am using Vue 2.

When does React re-render the parent component?

I'm currently learning React, and trying to get a sense of how components re-render. I have this parent component which renders three items. Each item just renders an <li>
function App() {
console.log("Parent Rerendered");
return (
<div>
<ul>
<Item1 />
<Item2 />
<Item3 />
</ul>
</div>
);
}
Item2 is a bit different because it also renders an "x" that will un-render the component when it's clicked:
function Item2() {
const [visible, setVisible] = useState(true);
const makeInvisible = () => {
setVisible(false);
};
console.log("Item 2 Rerendered");
return visible ? (
<div>
<li>
Second Item <span onClick={makeInvisible}>X</span>
</li>
</div>
) : null;
}
When I test this in my browser and click the "x", I can see from the console that Item2 gets re-rendered. However, none of the other components get re-rendered including the parent component. However the parent component does change, so how does this happen without re-rendering it.
If that's a bit confusing, here's an illustration of the initial state, my expectations, and reality. What am I misunderstanding about how React re-renders components?
A component rerenders when it sets state, or when its parent rerenders1. App has no state and no parent, so it will never rerender. It doesn't need to though. React saves the virtual DOM from the previous render, so it still knows that App is supposed to be a div surrounding a ul surrounding an Item1, Item2, and Item3. If the Item2 rerenders, and returns a null instead of a div, react will update the part of the real DOM that the Item2 is responsible for, by removing the div. The rest of the page remains intact
1) or if a context it consumes changes, or in a class component when you call forceUpdate. But for most cases, it's just state and parent that matter.
Instead of clicking onto <Item2 /> go to the Dev-tools -> Explorer -> select the Element and press delete. The view will also change, the gap will close, without react being involved at all.
React is responsible to update the DOM, the layout is done by the browser. So when <Item2 /> decides it wants to be rendered as null instead of a div>li (??? invalid markup ) and therefore removes the respective DOM-nodes, the browser will update the layout.
And the parent component has nothing to do with all that.

How to scroll down to hidden section

I have a section that is made out of 2 components:
trigger component
show/hide component
Basically when I click on trigger component, new component under will appear. This is handled simple by useState
const [toShow, setToShow] = useState(0);
And then I am using onClick method:
onClick={() => setToShow(1)}
Showing the element under trigger component:
{toShow === 1 && (
<div className="show-box" id="myHiddenComponent">
<HiddenComponent />
</div>
)}
Problem is, I need to access the hidden component with id="myHiddenComponent" from my Navbar. That means, the component will be not set to show. But link should understand that it has to set it to be opened and then scroll to the component. Is something like that possible with React ?
Right now I am using Hashlink
<HashLink smooth to='#myHiddenComponent'>
GO TO HIDDEN SECTON
</HashLink>
But that does not work unfortunately, since the section is hidden.
you need to set state of toShow to 1 onClick on HashLink component

Reactjs material ui prevent re-render tabs on enter

I have built a material-ui based UI containing tabs in reactJS. Anytime a tab is selected, the content under that tab reloads which is causing a major performance issue because I am displaying an iFrame under one those tabs. I tried to use React.memo to ensure that the screen does not re-render because there is no change in the props but it still does.
Here is the code -
Code sandbox link
Is there a way, that once the iFrame is loaded for the first time and I switch between tabs, the iframe does not get re-rendered again?
You check if the value of the current tab equals the index of the current tab, and only if they are equal you display the content.
Instead - just keep the content and have the Typography component control the visibility of it's content (which you already have, using the hidden inside the Typography component.
<Typography
component="div"
role="tabpanel"
hidden={value !== index}
id={`simple-tabpanel-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{<Box p={3}>{children}</Box>}
</Typography>
Note that the content will be rendered, so if you have a lot of content inside/requests to the backend/etc - all of those will be part of your DOM, even if you don't see them.
TypeScript solution:
Wrap the tab display component in a memo() function call
Wrap the display component with the control logic (<div style={...})
Tab change won't re-render the DOM anymore; size of tab content naturally flows by tab display component size. Flushing/update can be triggered by state changes in tab display component.
Example code:
const SomeTabDisplayComponent = memo(() => {
return <div>Whatever the tab displays</div>
})
const getVisibilityStyle = (hiddenCondition: boolean): any => {
if (hiddenCondition) {
return {
visibility: 'hidden',
height: 0,
};
}
return {
visibility: 'visible',
height: 'inherit',
};
};
<div style={getVisibilityStyle(value !== index)}>
<SomeTabDisplayComponent />
</div>
This solution has many advantages over the prev. answer. It doesn't use another component; doesn't mis-use "Typography" (<p> tag is not meant to include block content! Doing this is bad for SEO and accessibility etc.; violates web standards.); It doesn't depend on Typography's it's internal "hidden" implementation (if that one changes in the future, the upper solution will break) and it gives full control over when the re-render/DOM flush happens.

Reload angular component with button click

I working on a angular 8 application. In that application I want to reload a component, when a button clicked which is inside of another component. I found a way to do that with router, first navigate to sample component and then navigate to actual component as shown in below code.
this.router.navigateByUrl('/SampleComponent', { skipLocationChange: true });
this.router.navigate(["yourLandingComponent"]);
But in this application I don't have used router. This is simple, single page application. I have used ngIf to render components as shown in below.
<div class="row main-wrapper">
<app-section-rental class="container-fluid p-0" *ngIf="tabset.tab0"></app-section-rental>
<app-section-insuarance class="container-fluid p-0" *ngIf="tabset.tab1"></app-section-insuarance>
<app-section-additionals class="container-fluid p-0" *ngIf="tabset.tab2"></app-section-additionals>
<app-section-optionals class="container-fluid p-0" *ngIf="tabset.tab3"></app-section-optionals>
<app-price-breakdown class="container-fluid p-0" *ngIf="tabset.tab4"></app-price-breakdown>
</div>
So I want to know how to reload my component with a button click, which is inside of another component.
I also found another way to do this with angular subscription. But the problem is I that subscription get an element, I don't have to change any state which make any change in HTML. So I don't know whether my component get reloaded or not. Is it compulsory to do any change in DOM element, in order to reload a component ?
You could use Obersavables from rxjs.
This Observable contains the data displayed/updated in you component.
private _testSubject = new BehaviorSubject<string>('old data');
testObservable$: Observable<string> = this._testSubject.asObservable();
The following function will update your data:
public refresh(){
this._testSubject.next('new Data');
}
Call this function on you refresh-button's onClick.
And finally you can use your Observable in your components html like that:
<div>
{{(testObservable$|async)}}
</div>
Hope that helps!
EDIT:
As I noticed in your comments, your refresh button is in an parent component. In this case you could implement your observable in your parent component and work with an input in your comopnent:
#Input()
yourObservable: Observable<string>;
and in your parent component:
<app-your-compomemt [yourObservable]="testObservable$"></app-your-compomemt>

Categories

Resources