web-dev-qa-db-ja.com

Material-UI TabsとReact Router 4の統合?

新しい反応ローター構文は、Linkコンポーネントを使用してルートを移動します。しかし、これをどのようにmateriaul-uiと統合できますか?

私の場合、メインナビゲーションシステムとしてタブを使用しているため、理論的には次のようなものが必要です。

const TabLink = ({ onClick, href, isActive, label }) => 
  <Tab
    label={label}
    onActive={onClick}
  />



export default class NavBar extends React.Component {
  render () {
    return (
      <Tabs>
        <Link to="/">{params => <TabLink label="Home" {...params}/>}</Link>
        <Link to="/shop">{params => <TabLink label="shop" {...params}/>}</Link>
        <Link to="/gallery">{params => <TabLink label="gallery" {...params}/>}</Link>
      </Tabs>
    )
  }
}

しかし、レンダリング時に、material-uiはTabsの子がTabコンポーネントでなければならないというエラーをスローします。進む方法は何でしょうか?タブのisActiveプロップを管理するにはどうすればよいですか?

前もって感謝します

25
Daniel Ramos

私のインストラクターはReact Router 4.0のwithRouterを使用してTabsコンポーネントをラップし、次のような履歴メソッドを有効にしました。

import React, {Component} from "react";
import {Tabs, Tab} from 'material-ui';
import { withRouter } from "react-router-dom";

import Home from "./Home";
import Portfolio from "./Portfolio";

class NavTabs extends Component {

 handleCallToRouter = (value) => {
   this.props.history.Push(value);
 }

  render () {
     return (
      <Tabs
        value={this.props.history.location.pathname}
        onChange={this.handleCallToRouter}
        >
        <Tab
          label="Home"
          value="/"
        >
        <div>
           <Home />
        </div>
        </Tab>
        <Tab
          label="Portfolio"
          value="/portfolio"
            >
          <div>
            <Portfolio />
          </div>
        </Tab>
      </Tabs>           
    )
  }
}

export default withRouter(NavTabs)  

BrowserRouterをindex.jsに追加するだけで準備完了です。

13
gkatchmar

別のソリューション( https://codesandbox.io/s/l4yo482pll )ハンドラーもHOCもなく、純粋な反応ルーターとマテリアルUIコンポーネントのみ:

import React, { Fragment } from "react";
import ReactDOM from "react-dom";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import { Switch, Route, Link, BrowserRouter, Redirect } from "react-router-dom";

function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <Route
          path="/"
          render={({ location }) => (
            <Fragment>
              <Tabs value={location.pathname}>
                <Tab label="Item One" value="/" component={Link} to="/" />
                <Tab label="Item Two" value="/tab2" component={Link} to="/tab2" />
                <Tab
                  value="/tab3"
                  label="Item Three"
                  component={Link}
                  to="/tab3"
                />
              </Tabs>
              <Switch>
                <Route path="/tab2" render={() => <div>Tab 2</div>} />
                <Route path="/tab3" render={() => <div>Tab 3</div>} />
                <Route path="/" render={() => <div>Tab 1</div>} />
              </Switch>
            </Fragment>
          )}
        />
      </div>
    </BrowserRouter>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
34
Gildas Garcia

Material 1.0のベータ版を使用し、ブラウザのBack/Forwardをミックスに追加する別のソリューションを次に示します。

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Tabs, { Tab } from 'material-ui/Tabs';
import { withRouter } from "react-router-dom";
import Home from "./Home";
import Portfolio from "./Portfolio";

function TabContainer(props) {
  return <div style={{ padding: 20 }}>{props.children}</div>;
}

const styles = theme => ({
  root: {
    flexGrow: 1,
    width: '100%',
    marginTop: theme.spacing.unit * 3,
    backgroundColor: theme.palette.background.paper,
  },
});

class NavTabs extends React.Component {
  state = {
    value: "/",
  };

  componentDidMount() {
    window.onpopstate = ()=> {
      this.setState({
        value: this.props.history.location.pathname
      });
  }
}

  handleChange = (event, value) => {
    this.setState({ value });
    this.props.history.Push(value);
  };

  render() {
    const { classes } = this.props;
    const { value } = this.state;

    return (
      <div className={classes.root}>
        <AppBar position="static" color="default">
          <Tabs
            value={value}
            onChange={this.handleChange}
            scrollable
            scrollButtons="on"
            indicatorColor="primary"
            textColor="primary"
          >
            <Tab label="Home" value = "/" />
            <Tab label="Portfolio" value = "/portfolio"/>
          </Tabs>
        </AppBar>
        {value === "/" && <TabContainer>{<Home />}</TabContainer>}
        {value === "/portfolio" && <TabContainer>{<Portfolio />}</TabContainer>}
      </div>
    );
  }
}

NavTabs.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withRouter(withStyles(styles)(NavTabs));
2
gkatchmar

Material-uiで見られるエラーは、<Tab>コンポーネントが<Tabs>コンポーネントの直接の子としてレンダリングされることを期待しているためです。

ここで、スタイルを失うことなくリンクを<Tabs>コンポーネントに統合する方法を以下に示します。

import React, {Component} from 'react';
import {Tabs, Tab} from 'material-ui/Tabs';
import {Link} from 'react-router-dom';

export default class MyComponent extends Component {
    render() {
        const {location} = this.props;
        const {pathname} = location;

        return (
            <Tabs value={pathname}>
                <Tab label="First tab" containerElement={<Link to="/my-firs-tab-view" />} value="/my-firs-tab-view">
                    {/* insert your component to be rendered inside the tab here */}
                </Tab>
                <Tab label="Second tab" containerElement={<Link to="/my-second-tab-view" />} value="/my-second-tab-view">
                    {/* insert your component to be rendered inside the tab here */}
                </Tab>
            </Tabs>
        );
    }
}

タブの「アクティブ」プロパティを管理するには、<Tabs>コンポーネントでvalueプロパティを使用できます。また、各タブにvalueプロパティが必要です。両方のプロパティが一致すると、そのタブにアクティブなスタイルが適用されます。

2
erickpeniche

@gkatchmarが言うように、withRouter高次コンポーネントを使用できますが、context API。 @gkatchmarがwithRouterをすでに示しているので、context API。これは実験的なAPIであることに注意してください。

https://stackoverflow.com/a/42716055/3850405

import React, {Component} from "react";
import {Tabs, Tab} from 'material-ui';
import * as PropTypes from "prop-types";

export class NavTabs extends Component {
constructor(props) {
 super(props);
}

static contextTypes = {
    router: PropTypes.object
}

handleChange = (event: any , value: any) => {
    this.context.router.history.Push(value);
};

  render () {
     return (
      <Tabs
        value={this.context.router.history.location.pathname}
        onChange={this.handleChange}
        >
        <Tab
          label="Home"
          value="/"
        >
        <div>
           <Home />
        </div>
        </Tab>
        <Tab
          label="Portfolio"
          value="/portfolio"
            >
          <div>
            <Portfolio />
          </div>
        </Tab>
      </Tabs>           
    )
  }
}
1
Ogglas

React-Router browserHistoryコンポーネントの代わりにLinkを使用できます

_import { browserHistory } from 'react-router'

// Go to /some/path.
onClick(label) {
  browserHistory.Push('/${label}');
}

// Example for Go back
//browserHistory.goBack()

<Tabs>
  <Tab
    label={label}
    onActive={() => onClick(label)}
  />
</Tabs>
_

ご覧のように、browserHistoryへのターゲットをPush()するだけです。

1
Piotr O