I should be able to somehow use a <ListItem>
with a Link
in TypeScript.
I've found a few examples that suggest using:
<ListItem button component={Link} to="/somelink"></ListItem>
But I use TypeScript, and using to
attr throws a compilation error since to
is not a property of ListItem
.
create-react-app my-app --scripts-version=react-scripts-ts
to create a simple react app with TSreact-router
as dep and install itList
in the app template and try to add an item with <ListItem button component={Link} to="/somelink"></ListItem>
I'm trying to setup Material UI with react-router.
| Tech | Version |
|--------------|---------|
| Material-UI | next |
| React | 16.1.0 |
| browser | Chrome |
| etc | |
It's something we have already been discussing in https://github.com/callemall/material-ui/issues/8063#issuecomment-342330737.
@oliviertassinari ops, I haven't searched well enough 馃槃 But just to be clear, I should be using:
<ListItem component={props => <Link {...props} to="/about" />}>
// ...
</ListItem>
Right? At least that's the only variation that works for me without throwing any TS compilation errors.
@rolandjitsu Yes, I would encourage using this pattern.
@oliviertassinari thanks, I've just started with React and at this point all is a little confusing 馃槅
I think @rolandjitsu 's solution is the only way it could work becouse the ListItem
's typescript def. is fixed and adding Link
can not be dyamnically changed.
@rolandjitsu This soultion no longer work in @types/react 16.0.36 version. :(
@activebiz I'll give that a try tomorrow and see if it still works for me.
It seems when ListItem's innerRef is passed to Link, Link will not work properly. Try this:
<ListItem component={({innerRef,...props}) => <Link {...props} to="/about" />}
// ...
</ListItem>
I wrote my own component for that which seams to work fine and is reasonably type safe:
import * as React from 'react'
import { ListItem } from '@material-ui/core';
import { Link } from 'react-router-dom';
import { ListItemProps } from '@material-ui/core/ListItem';
import { LocationDescriptor } from 'history';
interface Props extends ListItemProps {
// ListItemProps and LinkProps both define an 'innerRef' property
// which are incompatible. Therefore the props `to` and `replace` are
// simply duplicated here.
to: LocationDescriptor
replace?: boolean
}
function createLink({innerRef, ...props}: Props) {
// Remove `innerRef` from properties as the interface
// is incompatible. The property `innerRef` should not be
// needed as the `ListItem` component already provides that
// feature with a different interface.
return <Link {...props}/>
}
export class ListItemLink extends React.PureComponent<Props> {
render() {
return <ListItem {...this.props} component={createLink}/>
}
}
I tried to write it as type safe as possible. That's the reason for a dedicated createLink
function, so that the compiler can shout at me if LinkProps
and ListItemProps
become incompatible in the future.
Usage:
<ListItemLink to="/about">... </ListItemLink>
This solution is more or less identical to the one suggested by @adimitris but also adds some extra type safety (due to createLink
) and wraps it all neatly together for a simpler usage.
The ripple effect seems to not be working when using @adimitris solution. Any idea why? I'm trying to figure out.
The ripple effect seems to not be working when using @adimitris solution. Any idea why? I'm trying to figure out.
@Nelrohd You need to create the link component outside of the render method. If you don't, the component reference will change at each render. React will consider it's a new component, unmount and remount it. You loose the ripple.
Same thing with Tab
or any other component that can be a Link
.
So far I found this:
<Tab label="Local" {...{component: Link, to: `/local`} as any}/>
Still an issue in 2020
Most helpful comment
@oliviertassinari ops, I haven't searched well enough 馃槃 But just to be clear, I should be using:
Right? At least that's the only variation that works for me without throwing any TS compilation errors.