Material-ui: react-routerと互換性のあるListItemを変換する

作成日 2017年08月30日  ·  21コメント  ·  ソース: mui-org/material-ui

ListListItemLinkコンポーネントにしたいと思います。

私が持っているDrawer構成部品List 、コンポーネントを
そのリストは4つのListItem構成されています。
私が達成したいのは、各ListItemをReactルーターLink変換することです。
ドロワーのonClickメソッドを変更し、クリックされたListItemのIDを取得してから、IDに基づいてウィンドウの場所をプログラムで変更しようとしました。
しかし、このアプローチは、reactの概念よりもjqueryishだと思います。
また、 ListItem componentプロップにLinkを追加しようとしましたが、エラーが発生しました( componentプロップでを使用したことがあります)ドキュメント)。
この要件を達成するための推奨される方法は何ですか?

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);
  • マテリアル-UI:1.0.6-ベータ
  • 反応:^ 15.6.1
  • ブラウザ:Chrome:60
  • react-router-dom:^ 4.1.2
question

最も参考になるコメント

これについては、 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>
  );
}

全てのコメント21件

次のように、 ListItemLinkラップできることがわかりました。

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

このアプローチでは、onClickメソッドも実行されます。
何か提案や改善はありますか?

次のように、ListItemをリンクでラップできることがわかりました。

このソリューションは意味的に有効ではありません。 ドキュメントで問題をどのように処理するかをご覧ください。

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

これも試すことができます

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

これについては、 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>
  );
}

ドキュメントに表示されません:
https://material-ui-next.com/demos/lists/
https://material-ui-next.com/demos/drawers/

これはReactRouterを使用する場合の一般的なことですが、 ListItem NavLinkを使用する方法が明確ではありません。
Buttoncomponent小道具?
そして、ボタンの小道具とコンポーネントの小道具は同じJSXタグで一緒に混合されていますか?
この種のミックスインとは何ですか?
なぜそんなに複雑なのですか?

@mehrdaadのソリューションを使用すると、リンクは通常のMUIリストのように見えますが、 @ oliviertassinariが提案したようにcomponent={Link}使用すると、スタイルが台無しになります。
(画像では、マウスは[ビルド]にカーソルを合わせていますが、2番目の項目には下線が引かれています...)

screen shot 2017-11-16 at 12 09 05

@ilyadorこのUIリンクスタイルの問題は解決されました。

@ zhangwei900808いいえ、それはまだ意味的に間違っています、それは<ul><a ..>...
https://codesandbox.io/s/lpwq74p30m

上記の答えを使用してください

@oliviertassinariもっと簡単な方法はありますか:

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

MenuItemButton二重ホバー効果を回避するために(まだわずかなガター/パディングがあります、別の問題)
これは面倒なので

デモ: httpscomponent={Link} to="/..."を使用していませんが、同じです)

@caubなぜ追加のボタンコンポーネントを導入するのですか? MenuItemのcomponentプロパティを使用できます。

@oliviertassinari ul > aが無効であるためhtml5 https://codesandbox.io/s/lpwq74p30m

@caub nav > aは有効です。

わかりました、ありがとう、元気ですhttps://codesandbox.io/s/lpwq74p30m

これが私の問題を解決した解決策です

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

したがって、ListItemを次のように使用します。
key = {index}
** {... {to:menu.link}} **
component = {リンク}
button = {true}
>>

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

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

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

@ mehrdaad @ oliviertassinariうまくいきました^ _ ^

これは私にとって完璧でした。 ありがとう!

MUI v4の移行後(私は4.3.1を使用)、「関数コンポーネントに参照を指定できません。この参照にアクセスしようとすると失敗します。React.forwardRef()を使用するつもりでしたか?」という理由で、最も投票された回答が失敗しました。

NavLinkコンポーネントを次のようなラッパーに置き換えました。

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

使用法:

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

@HugoGresseはい、 https://github.com/mui-org/material-ui/issues/7956#issuecomment-326908167を最新の回答で更新しました。 大丈夫かどうかお知らせください。

@oliviertassinariそれはしました。

ボタンのテキストの色がテーマパレットの色を考慮していない、forwardRefソリューションまたはComponent1のいずれかでまだ問題が発生しています。 テキストの色はpalette.type: 'dark'に一致するように白である必要がありますが、白です。

component小道具がなくても問題が解決しないため、おそらくMUIの変更にリンクされています。
Capture d'écran 2019-08-06 16 54 51

ここを読んでいる人のために、ListItemTextに追加の小道具を渡すことができます...

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

ところで、あなたの例は現在TSにあります。

これが私の問題を解決した解決策です

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

したがって、ListItemを次のように使用します。
key = {index}
** {... {to:menu.link}} **
component = {リンク}
button = {true}
>>

button={true}は、ドロワーのUI動作をリンクなしと同じにするだけです。

Typescriptでこれを行おうとしている他の人のために:

ListItemコンポーネントプロパティを使用してを指定する簡単な例ListItem実装としての要素。 Typescriptの秘訣は、ListItemの小道具でspread演算子(...)を使用して、このタイプのコンポーネントとListItemの「to」プロパティを指定すると通常発生する不要なTypescriptエラーを回避することです(TypescriptエラーTS2769プロパティ 'コンポーネント'はタイプ 'IntrinsicAttributesに存在しません...)

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

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

または、たとえば、ListItemでonClick関数を使用するだけの場合は次のようになります。


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

`` `

これは私のために働いた

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

MUI v4の移行後(私は4.3.1を使用)、「関数コンポーネントに参照を指定できません。この参照にアクセスしようとすると失敗します。React.forwardRef()を使用するつもりでしたか?」という理由で、最も投票された回答が失敗しました。

NavLinkコンポーネントを次のようなラッパーに置き換えました。

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

使用法:

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

ありがとう@HugoGresseこれは完全にうまく機能します:-)

このページは役に立ちましたか?
0 / 5 - 0 評価