在反应中,如何通过单击另一个组件中的图标来使模态显示在一个组件中?

时间:2018-11-21 16:43:32

标签: reactjs

我将React与Material UI结合使用。我有一个模式组件和一个ButtonAppBar。在ButtonAppBar内部,有一个我添加的购物车图标。我对React还是有点陌生​​,想知道单击购物车时显示模态的最佳方法。提前致谢。

这是我的App.js:

import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { Route } from 'react-router-dom';
import './App.css';
import ShopHome from './containers/ShopHome';
import ButtonAppBar from './components/ButtonAppBar';
import SimpleModalWrapped from './containers/ShoppingCartModal';

class App extends Component {

  handle
  render() {
    return (
      <BrowserRouter>
      <div>
        <ButtonAppBar />
        <SimpleModalWrapped />
        <Route exact path="/" component={ShopHome} />
      </div>
      </BrowserRouter>
    );
  }
}

export default App;

这是我的ButtonAppBar:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import SvgIcon from '@material-ui/core/SvgIcon';
import ShoppingCart from '@material-ui/icons/ShoppingCart';


const styles = {
  root: {
    flexGrow: 1,
  },
  grow: {
    flexGrow: 1,
  },
  menuButton: {
    marginLeft: -12,
    marginRight: 20,
  },
  appBar: {
    marginBottom: 50,
  }
};

function ButtonAppBar(props) {
  const { classes } = props;
  return (
    <div className={classes.root}>
      <AppBar style={styles.appBar} position="static">
        <Toolbar>
          <IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" color="inherit" className={classes.grow}>
            Velo-Velo
          </Typography>
          <Button color="inherit">Checkout</Button>
          <SvgIcon>
            <ShoppingCart />
          </SvgIcon>
        </Toolbar>
      </AppBar>
    </div>
  );
}

ButtonAppBar.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(ButtonAppBar);

这是模态:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Modal from '@material-ui/core/Modal';
import Button from '@material-ui/core/Button';

function rand() {
  return Math.round(Math.random() * 20) - 10;
}

function getModalStyle() {
  const top = 50 + rand();
  const left = 50 + rand();

  return {
    top: `${top}%`,
    left: `${left}%`,
    transform: `translate(-${top}%, -${left}%)`,
  };
}

const styles = theme => ({
  paper: {
    position: 'absolute',
    width: theme.spacing.unit * 50,
    backgroundColor: theme.palette.background.paper,
    boxShadow: theme.shadows[5],
    padding: theme.spacing.unit * 4,
  },
});

class SimpleModal extends React.Component {

  state = {
    open: false,
  };

  handleOpen = () => {
    console.log('clicked')
    this.setState({ open: true });
  };

  handleClose = () => {
    this.setState({ open: false });
  };

  render() {
    const { classes } = this.props;

    return (
      <div>
        {/* <Typography gutterBottom>Click to get the full Modal experience!</Typography>
        <Button onClick={this.handleOpen}>Open Modal</Button> */}
        <Modal
          aria-labelledby="simple-modal-title"
          aria-describedby="simple-modal-description"
          open={this.state.open}
          onClose={this.handleClose}
        >
          <div style={getModalStyle()} className={classes.paper}>
            <Typography variant="h6" id="modal-title">
              Text in a modal
            </Typography>
            <Typography variant="subtitle1" id="simple-modal-description">
              Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
            </Typography>
            <SimpleModalWrapped />
          </div>
        </Modal>
      </div>
    );
  }
}

SimpleModal.propTypes = {
  classes: PropTypes.object.isRequired,
};

// We need an intermediary variable for handling the recursive nesting.
const SimpleModalWrapped = withStyles(styles)(SimpleModal);

export default SimpleModalWrapped;

1 个答案:

答案 0 :(得分:0)

您最好的选择是使用Redux之类的东西。作为惰性策略,有一个包含两个组件的高阶组件。高阶组件可以具有单击该图标时需要运行的功能,并且它会更改高阶组件的状态。

说你有

import React, { Component } from 'react'
import ComponentWithIcon from './icon-holder'
import ModalComponent from './modal'

class OuterContainer extends Component {
  state = { modalOpen: false }
  
  setModal = openOrClose => this.setState({modalOpen: openOrClose})
  
  render(){
    const {setModal, state: { modalOpen } } = this
    return (
    <>
      <ComponentWithIcon
        handleModalClick={setModal}
      />
      <ModalComponent
        isOpen={modalOpen}
        handleModalClick={setModal}
      />
    </>
    )
  }
}

结果不是由Modal组件确定它是否处于打开状态(处于自己的状态),这意味着只有它知道OuterContainer将确定它当前是否处于打开状态。 。OuterContainer也是handleTheClickEvent的点击对象,因此图标将运行OuterComponent的功能到setState ...

此功能(clickHandler)和状态通过其子项传递给每个子组件。由于模态需要能够关闭,因此也可以从OuterComponent传入它,并且可以使用相同的state.modalOpen和可能是相同的传递动作(clickHandler)进行切换(或者如果您需要出于某种原因,您可以通过OuterComponent定义一个openModal / closeModal并传递两个要由模式运行的回调。

使用redux(带有react-redux),您将拥有一个<Provider>组件,它是其所有子组件的较高阶组件。提供者保持通过redux的createStore()生成的常规存储的状态,然后该存储获得操作操作中央存储的操作,并且由于它处于顶层,因此它能够注入其当前状态(或其中的特定部分) )到提供程序中包含的任何组件(每个组件)。这些组件中的每一个都能够使用dispatch()将消息发送到该提供程序,然后将这些操作分派给商店,从而导致商店被内部具有更新内容的新商店替换(例如,模式开了)。

import React from 'react'

const MyModal = ({isOpen, handleModal }) => (
  <div className={`modal ${isOpen ? 'is-showing' : 'is-hidden'}`}>
    <div
      className='toolbar'
    >
      <CloseButton onClick={() => handleModal(false)} />
    </div>
    <div>
    {/* Modal content */}
    </div>
  </>
)