Material-ui: Konversi ListItem kompatibel dengan react-router

Dibuat pada 30 Agu 2017  ·  21Komentar  ·  Sumber: mui-org/material-ui

Saya ingin membuat setiap ListItem dalam komponen List menjadi Link .

Saya memiliki komponen Drawer terdiri dari komponen List ,
Daftar itu terdiri dari 4 ListItem s.
Yang ingin saya capai adalah mengonversi setiap ListItem ke router React Link .
Saya mencoba untuk mengubah metode onClick laci, mendapatkan Id dari ListItem yang diklik dan kemudian secara terprogram mengubah lokasi jendela berdasarkan id.
Tapi saya pikir pendekatan ini lebih jqueryish daripada konsep bereaksi.
Saya juga mencoba menambahkan Link ke component prop di ListItem , tetapi menghasilkan kesalahan. (Saya telah melihat Anda telah menggunakan component prop di dokumen).
Apa cara yang direkomendasikan untuk mencapai persyaratan ini?

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import Drawer from 'material-ui/Drawer';
import List, { ListItem, ListItemIcon, ListItemText } from 'material-ui/List';
import Face from 'material-ui-icons/Face';
import Person from 'material-ui-icons/Person';
import Assignment from 'material-ui-icons/Assignment';
import Link from 'react-router-dom/Link';
import { FormattedMessage } from 'react-intl';

const styles = {
   list: {
      width: 250,
      flex: 'initial',
    },
};

 class UndockedDrawer extends Component {

   constructor() {
      super();
      this.onClick = this.onClick.bind(this);
    }

    onClick(e, data) {
       console.log(data);
       this.props.onRequestClose();
     }

   render() {
       const classes = this.props.classes;
        const sidebarListItems = (
     <div>
         <ListItem button >
            <ListItemIcon>
               <Person />
           </ListItemIcon>
            <ListItemText primary={<FormattedMessage id="user" />} />
          </ListItem>
    <ListItem button>
      <ListItemIcon>
        <Assignment />
      </ListItemIcon>
      <ListItemText primary={<FormattedMessage id="consultant" />} />
    </ListItem>
    <ListItem button>
      <ListItemIcon>
        <Face />
      </ListItemIcon>
      <ListItemText primary={<FormattedMessage id="student" />} />
    </ListItem>
  </div>
);

const sidebarList = (
  <div>
    <List className={classes.list} >
      {sidebarListItems}
    </List>
  </div>
);

return (
  <div>
    <Drawer
      anchor="right"
      open={this.props.open}
      onRequestClose={this.props.onRequestClose}
      onClick={this.onClick}
    >
      {sidebarList}
    </Drawer>
   </div>
   );
   }
 }

  UndockedDrawer.propTypes = {
     classes: PropTypes.shape({}).isRequired,
     open: PropTypes.bool.isRequired,
     onRequestClose: PropTypes.func.isRequired,
    };

   export default withStyles(styles)(UndockedDrawer);
  • Material-UI: 1.0.6-beta
  • Bereaksi: ^ 15.6.1
  • Browser: Chrome: 60
  • react-router-dom: ^ 4.1.2
question

Komentar yang paling membantu

Ini tercakup dalam dokumentasi: https://material-ui.com/components/buttons/#third -party-routing-library.

import React from 'react';
import { MemoryRouter as Router } from 'react-router';
import { Link, LinkProps } from 'react-router-dom';
import ListItem from '@material-ui/core/ListItem';
import { Omit } from '@material-ui/types';

// The usage of React.forwardRef will no longer be required for react-router-dom v6.
// see https://github.com/ReactTraining/react-router/issues/6056
const AdapterLink = React.forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => (
  <Link innerRef={ref as any} {...props} />
));

const CollisionLink = React.forwardRef<HTMLAnchorElement, Omit<LinkProps, 'innerRef' | 'to'>>(
  (props, ref) => <Link innerRef={ref as any} to="/getting-started/installation/" {...props} />,
);

export default function ButtonRouter() {
  return (
    <Router>
      <ListItem color="primary" component={AdapterLink} to="/">
        Simple case
      </ListItem>
      <ListItem component={CollisionLink}>Avoids props collision</ListItem>
    </Router>
  );
}

Semua 21 komentar

Saya menemukan, saya bisa membungkus ListItem menjadi Link sebagai berikut:

<Link to="users" style={{ textDecoration: 'none' }}>
      <ListItem button >
        <ListItemIcon>
          <Person />
        </ListItemIcon>
        <ListItemText primary={<FormattedMessage id="user" />} />
      </ListItem>
    </Link>

Dengan pendekatan ini, metode onClick juga akan diaktifkan.
Ada saran atau perbaikan?

Saya menemukan, saya bisa membungkus ListItem di Link sebagai berikut

Solusi ini tidak valid secara semantik. Lihat cara kami menangani masalah di dokumentasi:

https://github.com/callemall/material-ui/blob/92bd073015b9cc0dff3a26195fcb49153ddaab78/docs/src/modules/components/AppDrawerNavItem.js#L71 -L83

Anda juga bisa mencoba yang ini

https://github.com/callemall/material-ui/blob/92bd073015b9cc0dff3a26195fcb49153ddaab78/docs/src/pages/demos/buttons/FlatButtons.js#L40 -L42

Ini tercakup dalam dokumentasi: https://material-ui.com/components/buttons/#third -party-routing-library.

import React from 'react';
import { MemoryRouter as Router } from 'react-router';
import { Link, LinkProps } from 'react-router-dom';
import ListItem from '@material-ui/core/ListItem';
import { Omit } from '@material-ui/types';

// The usage of React.forwardRef will no longer be required for react-router-dom v6.
// see https://github.com/ReactTraining/react-router/issues/6056
const AdapterLink = React.forwardRef<HTMLAnchorElement, LinkProps>((props, ref) => (
  <Link innerRef={ref as any} {...props} />
));

const CollisionLink = React.forwardRef<HTMLAnchorElement, Omit<LinkProps, 'innerRef' | 'to'>>(
  (props, ref) => <Link innerRef={ref as any} to="/getting-started/installation/" {...props} />,
);

export default function ButtonRouter() {
  return (
    <Router>
      <ListItem color="primary" component={AdapterLink} to="/">
        Simple case
      </ListItem>
      <ListItem component={CollisionLink}>Avoids props collision</ListItem>
    </Router>
  );
}

Saya tidak melihatnya di dokumen:
https://material-ui-next.com/demos/lists/
https://material-ui-next.com/demos/drawers/

Ini adalah hal yang umum saat menggunakan React Router, tetapi tidak jelas bagaimana menggunakan NavLink dalam ListItem .
A Button dengan component prop?
Dan alat peraga tombol dan alat peraga komponen dicampur bersama pada tag JSX yang sama?
Mixin macam apa ini?
Mengapa begitu rumit?

Saat menggunakan solusi @mehrdaad , component={Link} seperti yang disarankan @oliviertassinari , gayanya menjadi kacau:
(Pada gambar, mouse mengarah ke "Build", tetapi item kedua mendapat garis bawah ...)

screen shot 2017-11-16 at 12 09 05

@ilyador Masalah gaya tautan UI ini telah diselesaikan.

@ zhangwei900808 Tidak, itu masih salah secara semantik, itu menghasilkan <ul><a ..>...
https://codesandbox.io/s/lpwq74p30m

Cukup gunakan jawaban yang disediakan di atas

@oliviertassinari Apakah ada cara yang lebih mudah untuk dilakukan:

const styles = {
    li: {
        '&:hover': {
            backgroundColor: 'transparent',
        },
    },
};
// ...
<MenuItem disableGutters className={classes.li}>
    <Button component={Link} to="/logout" ...

Untuk menghindari efek hover ganda, pada MenuItem dan pada Button (yang masih memiliki sedikit selokan / bantalan, masalah lain)
Karena ini tidak praktis

demo: https://codesandbox.io/s/nk834yk5pl (tidak menggunakan component={Link} to="/..." tapi itu sama)

@caub Mengapa Anda memperkenalkan komponen Tombol tambahan? Anda dapat menggunakan properti komponen pada MenuItem.

@oliviertassinari karena ul > a bukan html5 valid https://codesandbox.io/s/lpwq74p30m

@caub nav > a valid.

Oke, terima kasih, baik https://codesandbox.io/s/lpwq74p30m

Inilah solusi yang memecahkan masalah saya

<List>
        {menus.map((menu: any, index: any) => {
          return (
            <ListItem
              key={index}
              {...{ to: menu.link }}
              component={Link}
              button={true}
            >
              <ListItemIcon>{menu.icon}</ListItemIcon>
              <ListItemText primary={menu.text} />
            </ListItem>
          );
        })}
      </List>

Jadi gunakan saja ListItem sebagai
key = {index}
** {... {to: menu.link}} **
komponen = {Link}
tombol = {true}
>

import {Link} from 'react-router-dom'

<ListItem component={Link} to="/" button>

// or
<ListItem component={props => <Link to="/" {...props} />} button>

@mehrdaad @oliviertassinari Berhasil ^ _ ^

Ini sempurna untukku. Terima kasih!

Jawaban yang paling banyak dipilih gagal setelah migrasi MUI v4 (saya menggunakan 4.3.1) karena "Komponen fungsi tidak dapat diberikan referensi. Upaya untuk mengakses referensi ini akan gagal. Apakah Anda bermaksud menggunakan React.forwardRef ()?"

Saya telah mengganti komponen NavLink menjadi pembungkus seperti ini:

import React, { Component } from "react"
import { NavLink } from "react-router-dom"

/**
 * React Router Nav Link wrapper to forward the ref to fix "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
 *
 * From https://material-ui.com/guides/composition/#caveat-with-refs
 */
class NavLinkMui extends Component {
    render() {
        const { forwardedRef, ...props } = this.props
        return <NavLink {...props} ref={forwardedRef} />
    }
}

export default NavLinkMui

Pemakaian:

<ListItem
    button
    component={NavLinkMui}
    to='/'
>
    <ListItemIcon>
        <SlideshowIcon />
    </ListItemIcon>
</ListItem>

@HugoGresse Ya, Anda perlu menggunakan API ref maju. Anda seharusnya dapat menemukan contoh di dokumentasi. Saya telah memperbarui https://github.com/mui-org/material-ui/issues/7956#issuecomment -326908167 dengan jawaban terkini. Beri tahu kami jika tidak apa-apa.

@oliviertassinari melakukannya.

Saya masih mengalami beberapa masalah dengan solusi forwardRef atau Komponen dimana warna teks Tombol tidak memperhitungkan warna palet tema. Warna teks harus putih agar cocok dengan palette.type: 'dark' , tetapi putih.

Mungkin terkait dengan perubahan pada MUI karena tanpa properti component saya masih mengalami masalah.
Capture d'écran 2019-08-06 16 54 51

Bagi mereka yang membaca di sini, Anda dapat meneruskan props tambahan ke ListItemText ...

<ListItemText
    primaryTypographyProps={{
        color: 'textPrimary'
    }}
    primary="Dashboard"
/>

BTW, contoh Anda sekarang ada di TS.

Inilah solusi yang memecahkan masalah saya

<List>
        {menus.map((menu: any, index: any) => {
          return (
            <ListItem
              key={index}
              {...{ to: menu.link }}
              component={Link}
              button={true}
            >
              <ListItemIcon>{menu.icon}</ListItemIcon>
              <ListItemText primary={menu.text} />
            </ListItem>
          );
        })}
      </List>

Jadi gunakan saja ListItem sebagai
key = {index}
** {... {to: menu.link}} **
komponen = {Link}
tombol = {true}
>

button={true} membuat perilaku UI laci sama dengan tanpa tautan.

Untuk orang lain mencoba melakukan ini di Ketikan:

Contoh sederhana yang menggunakan properti komponen ListItem untuk menentukan fileelemen sebagai implementasi ListItem. Trik di Typecript adalah dengan menggunakan operator penyebaran (...) pada props ListItem untuk menyelinap melewati kesalahan Typecript yang tidak diinginkan dan tidak dibutuhkan yang menentukan jenis komponen ini dan properti "ke" untuk ListItem biasanya akan menghasilkan (Typecript kesalahan TS2769 Properti 'komponen' tidak ada pada tipe 'IntrinsicAttributes ...)

import { NavLink } from "react-router-dom";

        <List>
            <ListItem button={true} {...{ component: NavLink, to: "/Somewhere" }}>
                <ListItemIcon>
                    <ShoppingCartIcon />
                </ListItemIcon>
                <ListItemText primary="Orders" />
            </ListItem>
        </List>

atau sebagai alternatif jika Anda hanya ingin menggunakan fungsi onClick pada ListItem misalnya:


    <List>
        <ListItem button={true} {...{ onClick: () => alert("foo") }}>
            <ListItemIcon>
                <DashboardIcon />
            </ListItemIcon>
            <ListItemText primary="Dashboard" />
        </ListItem>
    </List>

``

Ini berhasil untuk saya

const NavLinkMui = React.forwardRef((props, ref) => (
  <NavLink {...props} activeClassName="Mui-selected" ref={ref} />
))
<ListItem button component={NavLinkMui} to={to}>{text}</ListItem>

Jawaban yang paling banyak dipilih gagal setelah migrasi MUI v4 (saya menggunakan 4.3.1) karena "Komponen fungsi tidak dapat diberikan referensi. Upaya untuk mengakses referensi ini akan gagal. Apakah Anda bermaksud menggunakan React.forwardRef ()?"

Saya telah mengganti komponen NavLink menjadi pembungkus seperti ini:

import React, { Component } from "react"
import { NavLink } from "react-router-dom"

/**
 * React Router Nav Link wrapper to forward the ref to fix "Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
 *
 * From https://material-ui.com/guides/composition/#caveat-with-refs
 */
class NavLinkMui extends Component {
    render() {
        const { forwardedRef, ...props } = this.props
        return <NavLink {...props} ref={forwardedRef} />
    }
}

export default NavLinkMui

Pemakaian:

<ListItem
    button
    component={NavLinkMui}
    to='/'
>
    <ListItemIcon>
        <SlideshowIcon />
    </ListItemIcon>
</ListItem>

Terima kasih @HugoGresse Ini bekerja dengan baik :-)

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

ryanflorence picture ryanflorence  ·  3Komentar

anthony-dandrea picture anthony-dandrea  ·  3Komentar

revskill10 picture revskill10  ·  3Komentar

TimoRuetten picture TimoRuetten  ·  3Komentar

ghost picture ghost  ·  3Komentar