新しい反応ローター構文は、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プロップを管理するにはどうすればよいですか?
前もって感謝します
私のインストラクターは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に追加するだけで準備完了です。
別のソリューション( 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);
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));
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
プロパティが必要です。両方のプロパティが一致すると、そのタブにアクティブなスタイルが適用されます。
@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>
)
}
}
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()
するだけです。