web-dev-qa-db-fra.com

Intégration des onglets Material-UI avec Reactor Routeur 4?

La nouvelle syntaxe react rotuer utilise le composant Link pour se déplacer sur les routes. Mais comment cela pourrait-il être intégré à materiaul-ui?

Dans mon cas, j'utilise des onglets comme système de navigation principal, donc en théorie, je devrais avoir quelque chose comme ceci:

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

Mais lors du rendu, material-ui génère une erreur indiquant que l'enfant de Tabs doit être un composant Tab. Quelle pourrait être la façon de procéder? Comment gérer l'accessoire isActive pour l'onglet?

Merci d'avance

25
Daniel Ramos

Mon instructeur m'a aidé à utiliser React withRouter du routeur 4.0 pour envelopper le composant Tabs pour activer les méthodes d'historique comme ceci:

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)  

Ajoutez simplement BrowserRouter à index.js et vous êtes prêt à partir.

13
gkatchmar

Une autre solution ( https://codesandbox.io/s/l4yo482pll ) sans gestionnaire ni HOC, juste de purs composants Reactor-Routeur et Material-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

Voici une autre solution, en utilisant la version bêta de Material 1.0 et en ajoutant le navigateur Back/Forward au mix:

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

L'erreur que vous voyez de matériel-ui est parce qu'il s'attend à avoir un <Tab> composant rendu en tant qu'enfant direct de <Tabs> composant.

Maintenant, voici un moyen que j'ai trouvé pour intégrer le lien dans le <Tabs> composant sans perdre les styles:

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>
        );
    }
}

Pour gérer la propriété 'active' des onglets, vous pouvez utiliser la propriété value dans le <Tabs> et vous devez également avoir une propriété value pour chaque onglet, donc lorsque les deux propriétés correspondent, il appliquera le style actif à cet onglet.

2
erickpeniche

Comme le dit @gkatchmar, vous pouvez utiliser withRouter un composant de haut niveau mais vous pouvez également utiliser context API. Étant donné que @gkatchmar a déjà montré avecRouter, je n'afficherai que context API. Gardez à l'esprit qu'il s'agit d'une API expérimentale.

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

Vous pouvez utiliser browserHistory au lieu du composant React-Router 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>

Comme vous le voyez, vous pouvez simplement Push() votre cible vers le browserHistory

1
Piotr O