我正在尝试实现子菜单(嵌套菜单)。
值得一提的是,我使用的是hydra组件,并且没有使用redux的经验(由于这个特定问题,几天前开始学习它)。
我遵循了material-ui上提供的嵌套列表https://material-ui.com/demos/lists/#nested-list的示例。还有来自的教程 https://marmelab.com/react-admin/Theming.html#using-a-custom-menu用于自定义菜单的实现。
所以我有几个问题。
1)我可以拥有仅用于处理菜单项切换的有状态组件(MyMenu)吗?
一个示例与react-admin无关,而仅仅是我的意思。
import React, { Component } from "react";
import { connect } from "react-redux";
import { addArticle } from "../actions/index";
const mapDispatchToProps = dispatch => {
return {
addArticle: article => dispatch(addArticle(article))
};
};
class ConnectedForm extends Component {
constructor() {
super();
this.state = {
title: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
const { title } = this.state;
const id = uuidv1();
this.props.addArticle({ title, id });
this.setState({ title: "" });
}
render() {
const { title } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="title">Title</label>
<input
type="text"
className="form-control"
id="title"
value={title}
onChange={this.handleChange}
/>
</div>
<button type="submit" className="btn btn-success btn-lg">
SAVE
</button>
</form>
);
}
}
const Form = connect(null, mapDispatchToProps)(ConnectedForm);
export default Form;
2)如果没有,我可以通过在存储中声明一个新状态来实现这一点,例如,打开:false,然后使用自定义的reducer来处理。
3(奖金)。如果这不是问题,那么如果有人可以让我朝着正确的方向开始学习,我将不胜感激,这样我就可以不费力地设法解决与这个令人惊奇的框架有关的问题:)
答案 0 :(得分:3)
react-admin演示现在在examples/demo/src/layout/Menu.js中显示了一种方法:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import compose from 'recompose/compose';
import SettingsIcon from '@material-ui/icons/Settings';
import LabelIcon from '@material-ui/icons/Label';
import { withRouter } from 'react-router-dom';
import {
translate,
DashboardMenuItem,
MenuItemLink,
Responsive,
} from 'react-admin';
import visitors from '../visitors';
import orders from '../orders';
import invoices from '../invoices';
import products from '../products';
import categories from '../categories';
import reviews from '../reviews';
import SubMenu from './SubMenu';
class Menu extends Component {
state = {
menuCatalog: false,
menuSales: false,
menuCustomers: false,
};
static propTypes = {
onMenuClick: PropTypes.func,
logout: PropTypes.object,
};
handleToggle = menu => {
this.setState(state => ({ [menu]: !state[menu] }));
};
render() {
const { onMenuClick, open, logout, translate } = this.props;
return (
<div>
{' '}
<DashboardMenuItem onClick={onMenuClick} />
<SubMenu
handleToggle={() => this.handleToggle('menuSales')}
isOpen={this.state.menuSales}
sidebarIsOpen={open}
name="pos.menu.sales"
icon={<orders.icon />}
>
<MenuItemLink
to={`/commands`}
primaryText={translate(`resources.commands.name`, {
smart_count: 2,
})}
leftIcon={<orders.icon />}
onClick={onMenuClick}
/>
<MenuItemLink
to={`/invoices`}
primaryText={translate(`resources.invoices.name`, {
smart_count: 2,
})}
leftIcon={<invoices.icon />}
onClick={onMenuClick}
/>
</SubMenu>
<SubMenu
handleToggle={() => this.handleToggle('menuCatalog')}
isOpen={this.state.menuCatalog}
sidebarIsOpen={open}
name="pos.menu.catalog"
icon={<products.icon />}
>
<MenuItemLink
to={`/products`}
primaryText={translate(`resources.products.name`, {
smart_count: 2,
})}
leftIcon={<products.icon />}
onClick={onMenuClick}
/>
<MenuItemLink
to={`/categories`}
primaryText={translate(`resources.categories.name`, {
smart_count: 2,
})}
leftIcon={<categories.icon />}
onClick={onMenuClick}
/>
</SubMenu>
<SubMenu
handleToggle={() => this.handleToggle('menuCustomer')}
isOpen={this.state.menuCustomer}
sidebarIsOpen={open}
name="pos.menu.customers"
icon={<visitors.icon />}
>
<MenuItemLink
to={`/customers`}
primaryText={translate(`resources.customers.name`, {
smart_count: 2,
})}
leftIcon={<visitors.icon />}
onClick={onMenuClick}
/>
<MenuItemLink
to={`/segments`}
primaryText={translate(`resources.segments.name`, {
smart_count: 2,
})}
leftIcon={<LabelIcon />}
onClick={onMenuClick}
/>
</SubMenu>
<MenuItemLink
to={`/reviews`}
primaryText={translate(`resources.reviews.name`, {
smart_count: 2,
})}
leftIcon={<reviews.icon />}
onClick={onMenuClick}
/>
<Responsive
xsmall={
<MenuItemLink
to="/configuration"
primaryText={translate('pos.configuration')}
leftIcon={<SettingsIcon />}
onClick={onMenuClick}
/>
}
medium={null}
/>
<Responsive
small={logout}
medium={null} // Pass null to render nothing on larger devices
/>
</div>
);
}
}
const mapStateToProps = state => ({
open: state.admin.ui.sidebarOpen,
theme: state.theme,
locale: state.i18n.locale,
});
const enhance = compose(
withRouter,
connect(
mapStateToProps,
{}
),
translate
);
export default enhance(Menu);
答案 1 :(得分:0)
我搜索了相同的问题。但是找不到嵌套菜单实现。所以我写了我自己的。检查下面的代码;
import React, { Component, createElement } from "react";
import {
Admin,
Resource,
Layout,
MenuItemLink,
getResources
} from "react-admin";
import jsonServerProvider from "ra-data-json-server";
import { withRouter } from "react-router-dom";
import { connect } from "react-redux";
import {
List,
ListItem,
Collapse,
ListItemText,
ListItemIcon
} from "@material-ui/core";
import { ExpandLess, ExpandMore, StarBorder, LabelIcon } from "@material-ui/icons";
import { withStyles } from "@material-ui/core/styles";
const menuStyles = theme => ({
nested: {
paddingLeft: theme.spacing.unit * 4
}
});
class Menu extends Component {
menuList = [
{ name: "A", label: "Top menu 1", icon: <LabelIcon /> },
{ name: "B", label: "Top menu 2", icon: <LabelIcon /> },
{ name: "c", label: "Top menu 3", icon: <LabelIcon /> }
];
constructor(props) {
super(props);
this.state = { open: "A" };
}
render() {
const { resources, onMenuClick, logout } = this.props;
return (
<div>
<List component="nav">
{this.menuList.map(menu => {
return (
<div key={menu.name}>
<ListItem
button
onClick={() => this.setState(state => ({ open: menu.name }))}
>
<ListItemIcon>{menu.icon}</ListItemIcon>
<ListItemText inset primary={menu.label} />
{this.state.open == menu.name ? (
<ExpandLess />
) : (
<ExpandMore />
)}
</ListItem>
<Collapse
in={this.state.open == menu.name}
timeout="auto"
unmountOnExit
>
<List component="div" disablePadding>
{resources
.filter(x => x.options.menu == menu.name)
.map((resource, i) => (
<MenuItemLink
key={"m" + i}
to={`/${resource.name}`}
primaryText={resource.options.label || resource.name}
leftIcon={
resource.icon
? createElement(resource.icon)
: undefined
}
onClick={onMenuClick}
className={this.props.classes.nested}
/>
))}
</List>
</Collapse>
</div>
);
})}
</List>
</div>
);
}
}
var MenuWithStyles = withStyles(menuStyles)(Menu);
const MyMenu = withRouter(
connect(state => ({
resources: getResources(state)
}))(MenuWithStyles)
);
const MyLayout = props => <Layout {...props} menu={MyMenu} />;
const App = () => (
<Admin
...
appLayout={MyLayout}
>
<Resource
...
options={{ label: 'Page 1' menu: "A" }}
/>
<Resource
...
options={{ label: 'Page 2' menu: "A" }}
/>
<Resource
...
options={{ label: 'Page 3' menu: "B" }}
/>
</Admin>
);