Проблема с созданием двух компонентов из одного в react.js

У меня есть один, более крупный компонент, который имеет несколько состояний и свойств. Этот компонент отвечает за заголовок и боковую панель. (перемещает меню влево). поэтому я хочу разбить его на два файла, но у меня это не получается.

Этот компонент имеет 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>
          );
        }
      }
    );

Вы не передаете никаких свойств компоненту Sidebar, который, как я полагаю, заменяет const drawer.

jolvera 04.10.2018 00:38
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
118
3

Ответы 3

Вы устанавливаете состояние open в компоненте заголовка, но не передаете его компоненту Sidebar в качестве опоры для управления им.

Я не могу это сделать как следует. Может ли кто-нибудь написать мне код правильно, чтобы я мог его проанализировать?

ReactX 03.10.2018 22:56

Я предполагаю, что вы выбираете компонент заголовка для управления свойством состояния 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>
  );

Другие вопросы по теме