Reputation: 2539
I have a simple Tabs setup with React Material UI (https://material-ui.com/components/tabs/) where the path value is set dynamically
export const Subnav: React.FC<Props> = ({ routes = [] }) => {
const { pathname } = useLocation();
const { push } = useHistory();
const handleChange = (e: ChangeEvent<{}>, path: string) => push(path);
return (
<Tabs
indicatorColor="primary"
onChange={handleChange}
scrollButtons="auto"
textColor="primary"
value={pathname}
variant="scrollable"
>
{routes.map(r => (
<Tab label={r.name} value={r.path} />
))}
</Tabs>
);
};
When I first load a page / navigate to one of the tab routes, the correct tab is selected, but the indicator is not shown. In order for the indicator to be shown I have to click the same tab again or select another.
Upvotes: 9
Views: 6223
Reputation: 101
export const Subnav: React.FC<Props> = ({ routes = [], render }) => {
const { pathname } = useLocation();
const { push } = useHistory();
const handleChange = (e: ChangeEvent<{}>, path: string) => push(path);
const ref = useRef();
useEffect(() => {ref.current.updateIndicator()}, [pathname, render])
return (
<Tabs
action={ref}
indicatorColor="primary"
onChange={handleChange}
scrollButtons="auto"
textColor="primary"
value={pathname}
variant="scrollable"
>
{routes.map(r => (
<Tab label={r.name} value={r.path} />
))}
</Tabs>
);
};
Put into props.render your anything dynamically value
Upvotes: 0
Reputation: 7980
My solution based on above ones but a bit different. The difference is that I update the indicator via a deferred call (setTimeout
) with 400ms
delay. Don't know real reason.
Below my definition of Mui-Tabs wrapper
import * as React from 'react';
import MaterialTabs, { TabsActions } from '@material-ui/core/Tabs';
import { withStyles } from '@material-ui/core';
import { IProps } from './types';
import styles from './styles';
class Tabs extends React.PureComponent<IProps> {
tabsActions: React.RefObject<TabsActions>;
constructor(props) {
super(props);
this.tabsActions = React.createRef();
}
/**
* Read more about this here
* - https://github.com/mui-org/material-ui/issues/9337#issuecomment-413789329
*/
componentDidMount(): void {
setTimeout(() => {
if (this.tabsActions.current) {
this.tabsActions.current.updateIndicator();
}
}, 400); // started working only with this timing
}
render(): JSX.Element {
return (
<MaterialTabs
action={this.tabsActions}
indicatorColor="primary"
variant="scrollable"
scrollButtons="auto"
{...this.props}
/>
);
}
}
export default withStyles(styles)(Tabs);
Upvotes: -1
Reputation: 721
For this, there is one more way to handle this.
In React material UI there is component <Grow/>
you can warp <Tabs/>
within <Grow/>
and <Grow/>
will correct the indicator position.
Following is the example:
<Grow in={true}>
<Tabs
action={ref => ref.updateIndicator()}
>
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
<Tabs>
</Grow>
Upvotes: 7
Reputation: 2539
This was resolved via https://github.com/mui-org/material-ui/issues/20527
You need to manually trigger the updateIndicator method. Easiest way to do this, is to call a resize event (which triggers the method)
useEffect(() => {
window.dispatchEvent(new CustomEvent("resize"));
}, []);
Alternatively add a ref to the actions prop and call the method directly. Still seems like a non-ideal solution, but it is what the maintainer provided.
Upvotes: 5