在react.js中从一个组件创建两个组件的问题

时间:2018-10-03 20:39:24

标签: javascript reactjs

我有一个更大的组件,具有多个状态和道具。此组件负责页眉和侧边栏。 (将菜单移到左侧)。所以我想将其拆分为两个文件,但是做得不好。

此组件具有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>
          );
        }
      }
    );

3 个答案:

答案 0 :(得分:0)

您正在标题组件中设置状态open,但没有将其传递给Sidebar组件作为控制它的道具。

答案 1 :(得分:0)

我假设您选择Header Component来管理open状态属性,这样:

您的标头组件应处于打开状态,并且具有切换功能。

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

答案 2 :(得分:0)

您没有传递道具,这可能是问题所在。但是类似的事情应该起作用。

实现此目标的最佳方法是使用无状态组件,并传递您需要呈现的数据。

您可以这样编写主要组件:

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