У меня есть один, более крупный компонент, который имеет несколько состояний и свойств. Этот компонент отвечает за заголовок и боковую панель. (перемещает меню влево). поэтому я хочу разбить его на два файла, но у меня это не получается.
Этот компонент имеет const Drawer, и это именно то, что я хотел бы переместить в другой файл (вместе с состоянием и всеми стилями) Это мой единственный, более крупный компонент:
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import classNames from 'classnames';
import Drawer from '@material-ui/core/Drawer';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Divider from '@material-ui/core/Divider';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import ListItem from '@material-ui/core/ListItem';
import List from '@material-ui/core/List';
// import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
const drawerWidth = 240;
const styles = theme => ({
root: {
flexGrow: 1
},
appFrame: {
height: 430,
zIndex: 1,
overflow: 'hidden',
position: 'relative',
display: 'flex',
width: '100%'
},
appBar: {
position: 'absolute',
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
appBarShift: {
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
})
},
'appBarShift-left': {
marginLeft: drawerWidth
},
'appBarShift-right': {
marginRight: drawerWidth
},
menuButton: {
marginLeft: 12,
marginRight: 20
},
hide: {
display: 'none'
},
drawerPaper: {
position: 'relative',
width: drawerWidth
},
drawerHeader: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar
},
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing.unit * 3,
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
'content-left': {
marginLeft: -drawerWidth
},
'content-right': {
marginRight: -drawerWidth
},
contentShift: {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
})
},
'contentShift-left': {
marginLeft: 0
},
'contentShift-right': {
marginRight: 0
}
});
export default withStyles(styles, { withTheme: true })(
class Header extends Component {
state = {
open: true,
anchor: 'left'
};
handleDrawerToggle = () => {
const open = this.state.open;
this.setState({
open: !open
});
};
render() {
const { classes, theme } = this.props;
const { anchor, open } = this.state;
const drawer = (
<Drawer
variant = "persistent"
anchor = {anchor}
open = {open}
classes = {{
paper: classes.drawerPaper
}}
>
<div className = {classes.drawerHeader} />
<Divider />
<List component = "nav">
<ListItem button>
<ListItemText primary = "One ListItem" />
</ListItem>
<ListItem button>
<ListItemText primary = "Two ListItem" />
</ListItem>
</List>
</Drawer>
);
return (
<div className = {classes.appFrame}>
<AppBar
className = {classNames(classes.appBar, {
[classes.appBarShift]: open,
[classes[`appBarShift-${anchor}`]]: open
})}
>
<Toolbar disableGutters = {!open}>
<IconButton
color = "inherit"
aria-label = "Open drawer"
onClick = {this.handleDrawerToggle}
className = {classNames(classes.menuButton)}
>
<MenuIcon />
</IconButton>
<Typography variant = "title" color = "inherit" noWrap>
Example Text
</Typography>
</Toolbar>
</AppBar>
{drawer}
<main
className = {classNames(classes.content, classes[`content-${anchor}`], {
[classes.contentShift]: open,
[classes[`contentShift-${anchor}`]]: open
})}
>
<div className = {classes.drawerHeader} />
<Typography>You think water moves fast? You should see ice.</Typography>
</main>
</div>
);
}
}
);
И это моя попытка разбить это на два файла, но это не работает. Он успешно компилируется, но отображается некорректно.
Header.js:
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import classNames from 'classnames';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import Sidebar from './Sidebar';
const drawerWidth = 240;
const styles = theme => ({
root: {
flexGrow: 1
},
appFrame: {
height: 430,
zIndex: 1,
overflow: 'hidden',
position: 'relative',
display: 'flex',
width: '100%'
},
appBar: {
position: 'absolute',
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
appBarShift: {
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
})
},
'appBarShift-left': {
marginLeft: drawerWidth
},
'appBarShift-right': {
marginRight: drawerWidth
},
menuButton: {
marginLeft: 12,
marginRight: 20
},
hide: {
display: 'none'
},
drawerPaper: {
position: 'relative',
width: drawerWidth
},
drawerHeader: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar
},
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing.unit * 3,
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
'content-left': {
marginLeft: -drawerWidth
},
'content-right': {
marginRight: -drawerWidth
},
contentShift: {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
})
},
'contentShift-left': {
marginLeft: 0
},
'contentShift-right': {
marginRight: 0
}
});
export default withStyles(styles, { withTheme: true })(
class Header extends Component {
state = {};
handleDrawerToggle = () => {
const open = this.props.open;
this.setState({
open: !open
});
};
render() {
const { classes, theme } = this.props;
const { anchor, open } = this.props;
return (
<div className = {classes.appFrame}>
<AppBar
className = {classNames(classes.appBar, {
[classes.appBarShift]: open,
[classes[`appBarShift-${anchor}`]]: open
})}
>
<Toolbar disableGutters = {!open}>
<IconButton
color = "inherit"
aria-label = "Open drawer"
onClick = {this.handleDrawerToggle}
className = {classNames(classes.menuButton)}
>
<MenuIcon />
</IconButton>
<Typography variant = "title" color = "inherit" noWrap>
Example Text
</Typography>
</Toolbar>
</AppBar>
<Sidebar />
<main
className = {classNames(classes.content, classes[`content-${anchor}`], {
[classes.contentShift]: open,
[classes[`contentShift-${anchor}`]]: open
})}
>
<div className = {classes.drawerHeader} />
<Typography>You think water moves fast? You should see ice.</Typography>
</main>
</div>
);
}
}
);
Sidebar.js:
import React, { Component } from 'react';
import ListItem from '@material-ui/core/ListItem';
import List from '@material-ui/core/List';
import { withStyles } from '@material-ui/core/styles';
// import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Drawer from '@material-ui/core/Drawer';
import Divider from '@material-ui/core/Divider';
const drawerWidth = 240;
const styles = theme => ({
drawerPaper: {
position: 'relative',
width: drawerWidth
},
drawerHeader: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar
}
});
export default withStyles(styles, { withTheme: true })(
class Sidebar extends Component {
state = {
open: true,
anchor: 'left'
};
render() {
const { classes, theme } = this.props;
const { anchor, open } = this.state;
return (
<Drawer
variant = "persistent"
anchor = {anchor}
open = {open}
classes = {{
paper: classes.drawerPaper
}}
>
<div className = {classes.drawerHeader} />
<Divider />
<List component = "nav">
<ListItem button>
<ListItemText primary = "One ListItem" />
</ListItem>
<ListItem button>
<ListItemText primary = "Two ListItem" />
</ListItem>
</List>
</Drawer>
);
}
}
);



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вы устанавливаете состояние open в компоненте заголовка, но не передаете его компоненту Sidebar в качестве опоры для управления им.
Я не могу это сделать как следует. Может ли кто-нибудь написать мне код правильно, чтобы я мог его проанализировать?
Я предполагаю, что вы выбираете компонент заголовка для управления свойством состояния open soo:
ваш компонент заголовка должен быть открыт, и он должен переключаться.
class Header extends Component {
state = {
open: true,
};
handleDrawerToggle = () => {
const open = this.state.open;
this.setState({
open: !open
});
};
render() { ...
<Sidebar open = {this.state.open} anchor = "left" />
}
}
и компонент боковой панели должен получать другие материалы из реквизита
const Sidebar = () => {
const { classes, theme, anchor, open } = this.props;
return (
...
)
};
Вы не передаете реквизит, это может быть проблемой. Но что-то вроде этого должно работать.
Лучший способ добиться этого - использовать компоненты без состояния и передавать данные, которые вам нужны для рендеринга.
Вы можете написать основной компонент так:
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import classNames from 'classnames';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Divider from '@material-ui/core/Divider';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import Sidebar from './Sidebar';
const drawerWidth = 240;
const styles = theme => ({
root: {
flexGrow: 1
},
appFrame: {
height: 430,
zIndex: 1,
overflow: 'hidden',
position: 'relative',
display: 'flex',
width: '100%'
},
appBar: {
position: 'absolute',
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
appBarShift: {
width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['margin', 'width'], {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
})
},
'appBarShift-left': {
marginLeft: drawerWidth
},
'appBarShift-right': {
marginRight: drawerWidth
},
menuButton: {
marginLeft: 12,
marginRight: 20
},
hide: {
display: 'none'
},
drawerPaper: {
position: 'relative',
width: drawerWidth
},
drawerHeader: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar
},
content: {
flexGrow: 1,
backgroundColor: theme.palette.background.default,
padding: theme.spacing.unit * 3,
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen
})
},
'content-left': {
marginLeft: -drawerWidth
},
'content-right': {
marginRight: -drawerWidth
},
contentShift: {
transition: theme.transitions.create('margin', {
easing: theme.transitions.easing.easeOut,
duration: theme.transitions.duration.enteringScreen
})
},
'contentShift-left': {
marginLeft: 0
},
'contentShift-right': {
marginRight: 0
}
});
export default withStyles(styles, { withTheme: true })(
class Header extends Component {
state = {
open: true,
anchor: 'left'
};
handleDrawerToggle = () => {
const open = this.state.open;
this.setState({
open: !open
});
};
render() {
const { classes, theme } = this.props;
const { anchor, open } = this.state;
return (
<div className = {classes.appFrame}>
<AppBar
className = {classNames(classes.appBar, {
[classes.appBarShift]: open,
[classes[`appBarShift-${anchor}`]]: open
})}
>
<Toolbar disableGutters = {!open}>
<IconButton
color = "inherit"
aria-label = "Open drawer"
onClick = {this.handleDrawerToggle}
className = {classNames(classes.menuButton)}
>
<MenuIcon />
</IconButton>
<Typography variant = "title" color = "inherit" noWrap>
Example Text
</Typography>
</Toolbar>
</AppBar>
<Sidebar anchor = {anchor} open = {open} classes = {classes} />
<main
className = {classNames(classes.content, classes[`content-${anchor}`], {
[classes.contentShift]: open,
[classes[`contentShift-${anchor}`]]: open
})}
>
<div className = {classes.drawerHeader} />
<Typography>You think water moves fast? You should see ice.</Typography>
</main>
</div>
);
}
}
);
И компонент Sidebar вроде:
import Drawer from '@material-ui/core/Drawer';
import ListItem from '@material-ui/core/ListItem';
import List from '@material-ui/core/List';
import ListItemText from '@material-ui/core/ListItemText';
const Sidebar = ({ anchor, open, classes }) => (
<Drawer
variant = "persistent"
anchor = {anchor}
open = {open}
classes = {{
paper: classes.drawerPaper
}}
>
<div className = {classes.drawerHeader} />
<Divider />
<List component = "nav">
<ListItem button>
<ListItemText primary = "One ListItem" />
</ListItem>
<ListItem button>
<ListItemText primary = "Two ListItem" />
</ListItem>
</List>
</Drawer>
);
Вы не передаете никаких свойств компоненту
Sidebar, который, как я полагаю, заменяетconst drawer.