Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cannot use react-router Link with ListItem in TypeScript #9106

Closed
1 task done
rolandjitsu opened this issue Nov 12, 2017 · 13 comments
Closed
1 task done

cannot use react-router Link with ListItem in TypeScript #9106

rolandjitsu opened this issue Nov 12, 2017 · 13 comments
Labels
duplicate This issue or pull request already exists

Comments

@rolandjitsu
Copy link
Contributor

  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

I should be able to somehow use a <ListItem> with a Link in TypeScript.

Current Behavior

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.

Steps to Reproduce (for bugs)

  1. Use create-react-app my-app --scripts-version=react-scripts-ts to create a simple react app with TS
  2. Add react-router as dep and install it
  3. Use a List in the app template and try to add an item with <ListItem button component={Link} to="/somelink"></ListItem>

Context

I'm trying to setup Material UI with react-router.

Your Environment

Tech Version
Material-UI next
React 16.1.0
browser Chrome
etc
@oliviertassinari oliviertassinari added the duplicate This issue or pull request already exists label Nov 12, 2017
@oliviertassinari
Copy link
Member

It's something we have already been discussing in #8063 (comment).

@rolandjitsu
Copy link
Contributor Author

@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.

@oliviertassinari
Copy link
Member

@rolandjitsu Yes, I would encourage using this pattern.

@rolandjitsu
Copy link
Contributor Author

@oliviertassinari thanks, I've just started with React and at this point all is a little confusing 😆

@activebiz
Copy link

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.

@activebiz
Copy link

@rolandjitsu This soultion no longer work in @types/react 16.0.36 version. :(

@rolandjitsu
Copy link
Contributor Author

@activebiz I'll give that a try tomorrow and see if it still works for me.

@adimitris
Copy link

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>

@bikeshedder
Copy link

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.

@Nelrohd
Copy link

Nelrohd commented Nov 10, 2018

The ripple effect seems to not be working when using @adimitris solution. Any idea why? I'm trying to figure out.

@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 12, 2018

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.

@kirill-konshin
Copy link

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}/>

@pietmichal
Copy link

Still an issue in 2020

@mui mui locked as resolved and limited conversation to collaborators Mar 3, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

8 participants