Как создать общий колонтитул для всех дочерних страниц в reactjs? - PullRequest
0 голосов
/ 16 марта 2020

Я использую reactjs в приложении, и мне нужно добавить страницу регистрации.

Мне нужен родительский макет с общим заголовком и страницей нижнего колонтитула.

Когда кто-нибудь нажмет кнопку «Зарегистрироваться», будут размещены тот же общий заголовок и нижний колонтитул.

-------------------Header.js------------------

import React from 'react';
import { fade,makeStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
// import Grid from '@material-ui/core/Grid';
import Icon from '@material-ui/core/Icon';
// import { browserHistory, Router, Route } from 'react-router';
import './App.css'; 
/* AppBar*/
//import { fade, makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import InputBase from '@material-ui/core/InputBase';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import MenuIcon from '@material-ui/icons/Menu';
import SearchIcon from '@material-ui/icons/Search';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MailIcon from '@material-ui/icons/Mail';
import NotificationsIcon from '@material-ui/icons/Notifications';
import MoreIcon from '@material-ui/icons/MoreVert';
/*App bar */

// import  ImgMediaCard from './ImgMediaCard';

// import GridList from '@material-ui/core/GridList';
// import GridListTile from '@material-ui/core/GridListTile';

// import DemoCarousel from './MCarousel';

// var gridListStyle = {  
//     marginLeft: "40px"
//   };

  const useStyles = makeStyles(theme => ({
    grow: {
      flexGrow: 1,
    },
    menuButton: {
      marginRight: theme.spacing(2),
    },
    title: {
      display: 'none',
      [theme.breakpoints.up('sm')]: {
        display: 'block',
      },
    },
    search: {
      position: 'relative',
      borderRadius: theme.shape.borderRadius,
      backgroundColor: fade(theme.palette.common.white, 0.15),
      '&:hover': {
        backgroundColor: fade(theme.palette.common.white, 0.25),
      },
      marginRight: theme.spacing(2),
      marginLeft: 0,
      width: '100%',
      [theme.breakpoints.up('sm')]: {
        marginLeft: theme.spacing(3),
        width: 'auto',
      },
    },
    searchIcon: {
      width: theme.spacing(7),
      height: '100%',
      position: 'absolute',
      pointerEvents: 'none',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
    },
    inputRoot: {
      color: 'inherit',
    },
    inputInput: {
      padding: theme.spacing(1, 1, 1, 7),
      transition: theme.transitions.create('width'),
      width: '100%',
      [theme.breakpoints.up('md')]: {
        width: 200,
      },
    },
    sectionDesktop: {
      display: 'none',
      [theme.breakpoints.up('md')]: {
        display: 'flex',
      },
    },
    sectionMobile: {
      display: 'flex',
      [theme.breakpoints.up('md')]: {
        display: 'none',
      },
    }  
  }));
  /*end App bar work*/
  const useGridStyles = makeStyles(theme => ({
    root: {
      flexGrow: 1,
    },
    paper: {
      // padding: theme.spacing(2),
      // textAlign: 'center',
      // color: theme.palette.text.secondary,
    },
  }));

function Header({ history }) {
    const Gridclasses = useGridStyles();
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = React.useState(null);
  const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null);

  const isMenuOpen = Boolean(anchorEl);
  const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);

  const handleProfileMenuOpen = event => {
    setAnchorEl(event.currentTarget);
  };

  const handleMobileMenuClose = () => {
    setMobileMoreAnchorEl(null);
  };

  const handleMenuClose = () => {
    setAnchorEl(null);
    handleMobileMenuClose();
  };

  const handleMobileMenuOpen = event => {
    setMobileMoreAnchorEl(event.currentTarget);
  };

  const onRegisterClick = () => {
    debugger;    
      history.push('/Register');      
 };

  const menuId = 'primary-search-account-menu';
  const renderMenu = (
    <Menu
      anchorEl={anchorEl}
      anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
      id={menuId}
      keepMounted
      transformOrigin={{ vertical: 'top', horizontal: 'right' }}
      open={isMenuOpen}
      onClose={handleMenuClose}
    >
      <MenuItem onClick={handleMenuClose}>Profile</MenuItem>
      <MenuItem onClick={handleMenuClose}>My account</MenuItem>
    </Menu>
  );

  const mobileMenuId = 'primary-search-account-menu-mobile';
  const renderMobileMenu = (
    <Menu
      anchorEl={mobileMoreAnchorEl}
      anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
      id={mobileMenuId}
      keepMounted
      transformOrigin={{ vertical: 'top', horizontal: 'right' }}
      open={isMobileMenuOpen}
      onClose={handleMobileMenuClose}
    >
      <MenuItem>   
      <Icon className="fa fa-plus-circle" />    
     </MenuItem>
      <MenuItem>     
        <IconButton aria-label="show 4 new mails" color="inherit">
          <Badge badgeContent={4} color="secondary">
            <MailIcon />
          </Badge>
        </IconButton>
        <p>Messages</p>
      </MenuItem>
      <MenuItem>
        <IconButton aria-label="show 11 new notifications" color="inherit">
          <Badge badgeContent={11} color="secondary">
            <NotificationsIcon />
          </Badge>
        </IconButton>
        <p>Notifications</p>
      </MenuItem>
      <MenuItem onClick={handleProfileMenuOpen}>
        <IconButton
          aria-label="account of current user"
          aria-controls="primary-search-account-menu"
          aria-haspopup="true"
          color="inherit"
        >
          <AccountCircle />
        </IconButton>
        <p>Profile</p>
      </MenuItem>
    </Menu>
  );
  return (

  <Paper className={Gridclasses.paper}>

      <div className={classes.grow}>
      <AppBar position="static">
        <Toolbar>
          <IconButton
            edge="start"
            className={classes.menuButton}
            color="inherit"
            aria-label="open drawer"
          >
            <MenuIcon />
          </IconButton>
          <Typography className={classes.title} variant="h6" noWrap>
            Shopping Center
          </Typography>
          <div className={classes.search}>
            <div className={classes.searchIcon}>
              <SearchIcon />
            </div>
            <InputBase
              placeholder="Search…"
              classes={{
                root: classes.inputRoot,
                input: classes.inputInput,
              }}
              inputProps={{ 'aria-label': 'search' }}
            />
          </div>
          <div className={classes.grow} />
          <div className={classes.sectionDesktop}>          
          <IconButton  aria-label="" color="inherit" onClick={onRegisterClick}> Sign Up             
            </IconButton> 
            <IconButton aria-label="show 4 new mails" color="inherit">
              <Badge badgeContent={4} color="secondary">
                <MailIcon />
              </Badge>
            </IconButton>
            <IconButton aria-label="show 17 new notifications" color="inherit">
              <Badge badgeContent={17} color="secondary">
                <NotificationsIcon />
              </Badge>
            </IconButton>
            <IconButton
              edge="end"
              aria-label="account of current user"
              aria-controls={menuId}
              aria-haspopup="true"
              onClick={handleProfileMenuOpen}
              color="inherit"
            >
              <AccountCircle />
            </IconButton>
          </div>
          <div className={classes.sectionMobile}>
            <IconButton
              aria-label="show more"
              aria-controls={mobileMenuId}
              aria-haspopup="true"
              onClick={handleMobileMenuOpen}
              color="inherit"
            >
              <MoreIcon />
            </IconButton>
          </div>
        </Toolbar>
      </AppBar>
      {renderMobileMenu}
      {renderMenu}
       </div>
        </Paper>
    );
}

export default Header;




-------------------Register.js----------------

import React from 'react';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import Input from '@material-ui/core/Input';
import FilledInput from '@material-ui/core/FilledInput';
import OutlinedInput from '@material-ui/core/OutlinedInput';
import InputLabel from '@material-ui/core/InputLabel';
import InputAdornment from '@material-ui/core/InputAdornment';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormControl from '@material-ui/core/FormControl';
import TextField from '@material-ui/core/TextField';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';

const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
  margin: {
    margin: theme.spacing(1),
  },
  withoutLabel: {
    marginTop: theme.spacing(3),
  },
  textField: {
    width: 200,
  },
}));

function RegisterBuyer() {
  const classes = useStyles();
  const [values, setValues] = React.useState({
    amount: '',
    password: '',
    weight: '',
    weightRange: '',
    showPassword: false,
  });

  const handleChange = prop => event => {
    setValues({ ...values, [prop]: event.target.value });
  };

  const handleClickShowPassword = () => {
    setValues({ ...values, showPassword: !values.showPassword });
  };

  const handleMouseDownPassword = event => {
    event.preventDefault();
  };

  return (
    <div className={classes.root}>
      <div>
        <TextField
          label="With normal TextField"
          id="standard-start-adornment"
          className={clsx(classes.margin, classes.textField)}
          InputProps={{
            startAdornment: <InputAdornment position="start">Kg</InputAdornment>,
          }}
        />
        <FormControl className={clsx(classes.margin, classes.withoutLabel, classes.textField)}>
          <Input
            id="standard-adornment-weight"
            value={values.weight}
            onChange={handleChange('weight')}
            endAdornment={<InputAdornment position="end">Kg</InputAdornment>}
            aria-describedby="standard-weight-helper-text"
            inputProps={{
              'aria-label': 'weight',
            }}
          />
          <FormHelperText id="standard-weight-helper-text">Weight</FormHelperText>
        </FormControl>
        <FormControl className={clsx(classes.margin, classes.textField)}>
          <InputLabel htmlFor="standard-adornment-password">Password</InputLabel>
          <Input
            id="standard-adornment-password"
            type={values.showPassword ? 'text' : 'password'}
            value={values.password}
            onChange={handleChange('password')}
            endAdornment={
              <InputAdornment position="end">
                <IconButton
                  aria-label="toggle password visibility"
                  onClick={handleClickShowPassword}
                  onMouseDown={handleMouseDownPassword}
                >
                  {values.showPassword ? <Visibility /> : <VisibilityOff />}
                </IconButton>
              </InputAdornment>
            }
          />
        </FormControl>
        <FormControl fullWidth className={classes.margin}>
          <InputLabel htmlFor="standard-adornment-amount">Amount</InputLabel>
          <Input
            id="standard-adornment-amount"
            value={values.amount}
            onChange={handleChange('amount')}
            startAdornment={<InputAdornment position="start">$</InputAdornment>}
          />
        </FormControl>
      </div>
      <div>
        <TextField
          label="With normal TextField"
          id="filled-start-adornment"
          className={clsx(classes.margin, classes.textField)}
          InputProps={{
            startAdornment: <InputAdornment position="start">Kg</InputAdornment>,
          }}
          variant="filled"
        />
        <FormControl className={clsx(classes.margin, classes.textField)} variant="filled">
          <FilledInput
            id="filled-adornment-weight"
            value={values.weight}
            onChange={handleChange('weight')}
            endAdornment={<InputAdornment position="end">Kg</InputAdornment>}
            aria-describedby="filled-weight-helper-text"
            inputProps={{
              'aria-label': 'weight',
            }}
          />
          <FormHelperText id="filled-weight-helper-text">Weight</FormHelperText>
        </FormControl>
        <FormControl className={clsx(classes.margin, classes.textField)} variant="filled">
          <InputLabel htmlFor="filled-adornment-password">Password</InputLabel>
          <FilledInput
            id="filled-adornment-password"
            type={values.showPassword ? 'text' : 'password'}
            value={values.password}
            onChange={handleChange('password')}
            endAdornment={
              <InputAdornment position="end">
                <IconButton
                  aria-label="toggle password visibility"
                  onClick={handleClickShowPassword}
                  onMouseDown={handleMouseDownPassword}
                  edge="end"
                >
                  {values.showPassword ? <Visibility /> : <VisibilityOff />}
                </IconButton>
              </InputAdornment>
            }
          />
        </FormControl>
        <FormControl fullWidth className={classes.margin} variant="filled">
          <InputLabel htmlFor="filled-adornment-amount">Amount</InputLabel>
          <FilledInput
            id="filled-adornment-amount"
            value={values.amount}
            onChange={handleChange('amount')}
            startAdornment={<InputAdornment position="start">$</InputAdornment>}
          />
        </FormControl>
      </div>
      <div>
        <TextField
          label="With normal TextField"
          id="outlined-start-adornment"
          className={clsx(classes.margin, classes.textField)}
          InputProps={{
            startAdornment: <InputAdornment position="start">Kg</InputAdornment>,
          }}
          variant="outlined"
        />
        <FormControl className={clsx(classes.margin, classes.textField)} variant="outlined">
          <OutlinedInput
            id="outlined-adornment-weight"
            value={values.weight}
            onChange={handleChange('weight')}
            endAdornment={<InputAdornment position="end">Kg</InputAdornment>}
            aria-describedby="outlined-weight-helper-text"
            inputProps={{
              'aria-label': 'weight',
            }}
            labelWidth={0}
          />
          <FormHelperText id="outlined-weight-helper-text">Weight</FormHelperText>
        </FormControl>
        <FormControl className={clsx(classes.margin, classes.textField)} variant="outlined">
          <InputLabel htmlFor="outlined-adornment-password">Password</InputLabel>
          <OutlinedInput
            id="outlined-adornment-password"
            type={values.showPassword ? 'text' : 'password'}
            value={values.password}
            onChange={handleChange('password')}
            endAdornment={
              <InputAdornment position="end">
                <IconButton
                  aria-label="toggle password visibility"
                  onClick={handleClickShowPassword}
                  onMouseDown={handleMouseDownPassword}
                  edge="end"
                >
                  {values.showPassword ? <Visibility /> : <VisibilityOff />}
                </IconButton>
              </InputAdornment>
            }
            labelWidth={70}
          />
        </FormControl>
        <FormControl fullWidth className={classes.margin} variant="outlined">
          <InputLabel htmlFor="outlined-adornment-amount">Amount</InputLabel>
          <OutlinedInput
            id="outlined-adornment-amount"
            value={values.amount}
            onChange={handleChange('amount')}
            startAdornment={<InputAdornment position="start">$</InputAdornment>}
            labelWidth={60}
          />
        </FormControl>
      </div>
    </div>
  );
}   

export default  Register

-------------------Index.js-------------------
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router,Switch, Route } from "react-router-dom";
import './index.css';
import Header from './Header.js'
import App from './App';
import * as serviceWorker from './serviceWorker';
import RegisterBuyer from './RegisterBuyer';

ReactDOM.render(   
    <Router>
       <Header />
    <Switch>
  <Route path="/RegisterBuyer" component={RegisterBuyer} />
  <Route exact path="/" component={App} />
  </Switch>
</Router>
   , document.getElementById('root'));

Я новичок ie с реакцией. Что мне делать в моем коде?

Я взял пример кода для меню и карт отсюда: https://material-ui.com

Application built with

{
  "react": "16.13.0", 
  "react-dom": "^16.13.0", 
  "react-redux": "^7.2.0",
  "redux": "^4.0.4"
  "@material-ui/core": "^4.9.5"
}

Проблема, которую я face получает сообщение об ошибке в следующей функции:

const onRegisterClick = () => {
    debugger;    
      history.push('/Register');      
 };

функция выше отображает ошибку ниже: TypeError: Невозможно прочитать свойство 'pu sh' из неопределенного

HTMLUnknownElement.callCallback node_modules / реагировать -dom / cjs / реагировать-dom.development. js: 188 invokeGuardedCallbackDev node_modules / реагировать-dom / cjs / react-dom.development. js: 237 invokeGuardedCallback node_modules / реагировать-dom / cjs / реагировать-dom.development . js: 292 invokeGuardedCallbackAndCatchFirstError node_modules / реагировать на dom / cjs / реагировать на дом. -dom / cjs / react-dom.development. js: 414 executeDispatchesAndRelease node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 3278 executeDispatchesAndReleaseTopLevel node_modules / реагировать-dom /cjs/react-dom.development.js:3287 forEachAccumulated node_modules / response-dom / cjs / Reaction-dom.development. js: 3259 runEventsInBatch node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 3304 runExtractedPluginEventsInBatch node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 3514 handleTopLevel node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 3558 batchedEventUpdates $ 1 dom / cjs / react-dom.development. js: 21902 batchedEventUpdates node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 1060 dispatchEventForLegacyPluginEventSystem node_modules / реагировать-dom / cjs / реагировать-dom. js: 3568 tryToDispatchEvent node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 4267 dispatchEvent /node_modules/react-dom/cjs/react-dom.development.js:4189 unstable_runWithPriordule node_modules /cjs/scheduler.development.js:653 runWithPriority $ 1 node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 11061 discreteUpdates $ 1 node_modules / реагировать-dom / cj s / react-dom.development. js: 21918 discreteUpdates node_modules / реагировать-dom / cjs / реагировать-dom.development. js: 1071 dispatchDiscreteEvent /node_modules/react-dom/cjs/react-dom.development.js: 4168 Вывод: Компонент SignUp должен отображаться в Layout (Parent) с одинаковыми общими верхним и нижним колонтитулами.

Я пытался следовать инструкциям и искал примеры реализации, но не смог решить / объяснить проблему хорошо.

1 Ответ

1 голос
/ 16 марта 2020

РЕДАКТИРОВАТЬ: Я обновил это для соответствия вашей концепции "основной" и "дочерней" страницы.


Реагировать на основе компонентов, так что любые компоненты, которые вы хотите рендеринг рядом или рядом с набором других компонентов должен быть структурирован таким образом.

Например, вы хотите визуализировать ваш Header компонент поверх остального содержимого страницы. Поэтому имеет смысл отобразить ваш Header рядом с содержимым страницы:

const MasterPage = () => {
    return (
        <>
            <Header />
            <ChildPage />
        </>
    )
}

const ChildPage = () => {
    return (
        <div>
          {/* ...child page content goes here... */}
        </div>
    )
}

Здесь мы определяем два компонента внутри нашего MasterPage компонента. Header отображается над компонентом ChildPage.

Компонент ChildPage содержит содержимое дочерней страницы, которое может быть любым. Независимо от того, что вы отображаете внутри ChildPage, Header всегда будет отображаться независимо.

Это означает, что вам не нужно многократно отображать заголовок в каждом отдельном компоненте страницы.

Теги <> и </> предназначены для React.Fragment, что означает, что вам не нужно оборачивать Header и ChildPage в дополнительные div, но Вы можете так же легко написать:

<div>
  <Header />
  <ChildPage />
</div>

Вы можете сделать то же самое для вашего Footer:

<>
  <Header />
  <ChildPage />
  <Footer />
</>

Ошибка, которую вы видите, заключается в том, что вам нужно импорт history. В настоящее время это undefined, поэтому вы пытаетесь преобразовать sh в неопределенный массив.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...