The Tab component renders all tab children components on first render. I think we should only render tab children if that tab has been visited.
This design is inefficient when each component is responsible for fetching it's own data. This is a common pattern when using frameworks like Apollo or Relay.
I wanted to write a Tab abstraction to achieve this, so I tried:
class LazyTab extends React.Component<any, any> {
constructor(props, context) {
super(props, context)
this.state = {
isActive: false
}
}
onActive(x) {
// Haven't tested this, but you get the intent..
this.setState({
isActive: true
})
}
render() {
let child = this.state.isActive ? this.props.children : <div />
return <Tab onActive={this.onActive.bind(this)}>
{child}
</Tab>
}
}
However I get a type error:
Warning: Tabs only accepts Tab Components as children.
Found function LazyTab(props, context) {
Any ideas? Thanks
Here is a great project with this feature: https://github.com/maslianok/react-responsive-tabs
<Tabs>
<Tab label="Campaigns">
<Campaigns />
</Tab>
<Tab lazy label="Activities"> //<-- load just when is activated
<Activities />
</Tab>
</Tabs>
But, this solution mounts the Tab's children each time the Tab is activated. Maybe what you want is that the Tab's children are mounted the first time the Tab is activated only?.
I have rejected @samhv PR as I think that we should separate concerns and keep flexibility.
(Aside from not accepting new features based on the master branch).
Regarding the next
branch, we have two simple presentational <Tabs />
&<Tab />
components. @dcworldwide Thanks for opening the issue, having a simple abstraction over that to handle the state sounds reasonable. But I'm not 100% sold on the idea as the implementation without seems simple enough:
<div>
<Tabs index={this.state.index} onChange={this.handleChange}>
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
</Tabs>
{this.state.index === 0 && <div>{'Item One'}</div>}
{this.state.index === 1 && <div>{'Item Two'}</div>}
{this.state.index === 2 && <div>{'Item Three'}</div>}
</div>
It's taken from this demo. We have a very close one on the master
branch.
Still we can build an abstraction for more complex feature or repetitive usage.
I'm closing the issue for now. We will see if there is a real value at providing a display view logic that can be lazy, intuitive to use, etc.
IMO having the possibility to get lazy tabs is critical for many projects.
@dcworldwide @samhv did you got a solution?
I switched to https://github.com/maslianok/react-responsive-tabs, yet i'd prefer to see this in mui. But @oliviertassinari is probably right that we can write such an abstraction ourselves should next allow it.
Once your tab's start implementing shouldComponentUpdate to optimise tab performance it becomes very app specific anyway..
@oliviertassinari has next solved this req? If so I think we can close :)
@dcworldwide No, it's up to users to implement it on the v1-beta branch. We don't provide any helpers. I have kept the issue open to see if people would be interested in implementing it. This is not something I will work on, but maybe someone else will :).
Yep I understood that. I agree with you stance. I just did it understand why the issue was still open.
Why this got closed?
My use case is the following:
I have a Tab which displays a leaflet
map. At the moment this causes 14 HTTP requests for map tiles and marker icons. This is unnecessary if the user doesn't event visit the corresponding tab.
Though I'd like to load this tab's content lazily (using something like <Tab lazy={true} />
for example).
Hello and sorry to be late for party. Lazy loading would be nice implementation :)
I may be missing something here, but is this not similar/identical to the unmountOnExit
functionality on the ExpansionPanel
?
<ExpansionPanel TransitionProps={{ unmountOnExit: true }} />
See docs: https://material-ui.com/components/expansion-panels/#performance
Caching the data to carry it over unmounts is a different issue of course, but (I think) we managed to get lazy loaded functionality as described above with expansion panels (inside of tabs, actually :-)).
So to @dcworldwide, @benneq and @airen29 : does that cover your use case(s)?
And to @oliviertassinari : would this be an acceptible approach (and reason to re-open this issue) or is there some conceptual difference between tabs and panels?
@dirkdevriendt let me try it with Expansion Panels. But making workaround for something that should be easily implemented into core is not a good approach :)
UP please add lazy feature, very important.
please add lazy feature, very important.
@NielsDom Please see #21250
@oliviertassinari thanks ok. About lazy load you can add this package inside each tab: https://www.npmjs.com/package/react-lazyload. It does the job
Most helpful comment
I may be missing something here, but is this not similar/identical to the
unmountOnExit
functionality on theExpansionPanel
?<ExpansionPanel TransitionProps={{ unmountOnExit: true }} />
See docs: https://material-ui.com/components/expansion-panels/#performance
Caching the data to carry it over unmounts is a different issue of course, but (I think) we managed to get lazy loaded functionality as described above with expansion panels (inside of tabs, actually :-)).
So to @dcworldwide, @benneq and @airen29 : does that cover your use case(s)?
And to @oliviertassinari : would this be an acceptible approach (and reason to re-open this issue) or is there some conceptual difference between tabs and panels?