0
votes

Problem: Store gets items from DB, and main component renders those Items with short info. On click I want to open modal component with detailed info about this product. My idea -> create variable where I would store info about selectedItem -> create variable which allows to appear modal component. And that is it first it writes info into selectedItem and with props it passes this variable to modal component and we give command to render this component with openModal. But where I have a problem is in openModalAction setState doesn't seem to be working. It simply doesn't change the state. I remember that setState is asynchronous, but writting this.setState inside this.setState didn't help and it looked weird. Anyhow main issue it says Item which it gets by props is undefined...

Should I try do it with functional component and will it make any differences? Is my logic right for doing modal windows and how would you do it ?

I have a pretty easy task seams like which I've done on Vue many times with no issues, but React drives me crazy every single day. But to be honest I starting like react, with his help I understand Vue even better, let's say React shows me how Vue works under the hood.

import React from 'react'
import { withStyles } from '@material-ui/styles';

import { Typography } from '@material-ui/core'
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Grid from '@material-ui/core/Grid'

import {inject, observer} from 'mobx-react'

import ItemModal from '@components/main/modalItem'

const useStyles = {
    media:{
        height: "145px"
    },
    modal: {
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
    }
}

let Main = inject("store")(observer(class Main extends React.Component {
    constructor(props){
        super(props);
        this.state = {
            selectedItem: {},
            openModal: false
        }
    }

    openModalAction = (el) => {
        this.setState({
            selectedItem: el,
            openModal: true
        })
    }

    closeModalAction = () => {
        this.setState({
            selectedItem: {},
            openModal: false
        })
    }

    modalComponent = () => {
        if(this.state.openModal)
            return (<ItemModal item = {this.selectedItem} />)
    }

    render(){
        const { classes } = this.props;
        let productModel = this.props.store.products; // gettting products instance from Mobx Store
        let productsDom = productModel.getAll.map((el, i) => { // making DOM
            return (
                <Grid item xs={3} key={i}>
                    <Card>
                    <CardContent>
                        <Typography variant="h4">{el.title}</Typography>
                        <Typography variant="subtitle1">{el.price}</Typography>
                    </CardContent>
                    <CardActions>
                        <Button color="secondary" onClick={ () => this.openModalAction(el) }>Quick look</Button>
                        <Button color="primary">Add to cart</Button>
                    </CardActions>
                 </Card>
            </Grid>)
        })

        return (

            <React.Fragment>
                {/*Modal item*/}
                { this.modalComponent() }

              
                {/*Items for sale*/}

                <div>
                 <Typography variant="h3" align="center" gutterBottom> Items </Typography>
                   <Grid container spacing={3}>
                            { productsDom }
                   </Grid>
                </div>
                </div>

            </React.Fragment>
        )
    }

}))

export default  withStyles(useStyles)(Main);

HERE IS MODAL COMPONENT

import React from "react"
import Card from "@material-ui/core/Card";
import CardContent from "@material-ui/core/CardContent";
import { Typography } from "@material-ui/core";
import {withStyles} from "@material-ui/styles";
import PropType from 'prop-types'

import Grid from '@material-ui/core/Grid'
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';

class ModalItem extends React.Component{

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

        return(
            <Card>
                <CardContent>
                    <Grid container>
                        <Grid item xs={6}>

                        </Grid>
                        <Grid item xs={6}>
                            <Typography variant="h3">{item.title}</Typography>
                            <Typography variant="subtitle1">{item.price}</Typography>
                            <Grid container item xs={12}>
                                <Grid item xs={6}>
                                    <TextField
                                    type="number"/>
                                </Grid>
                                <Grid item xs={6}>
                                    <Button color="primary">Add to cart</Button>
                                </Grid>
                            </Grid>
                            <Typography variant="subtitle2">Category</Typography>
                            <Button>Full review</Button>
                        </Grid>
                    </Grid>
                </CardContent>
            </Card>
        )
    }
}

ModalItem.propTypes = {
    item: PropType.object
}

export default  withStyles(useStyles)(ModalItem);
1
Can you provide a minimum working example on codesandbox or equivalent ?P.E. Joëssel
here is a git, file pages -> main.js thank you when you do npm run start will open up main page, just scroll all the way down you will see item list where you can press a button "Quick look up"Eldar Tailov

1 Answers

1
votes

You are close ! Works for me, I haven't test store

const useStyles = {
    media:{
        height: "145px"
    },
    modal: { // remove modal from here to put in the right file ->ModalItem
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
    }
}

let Main = inject("store")(observer(class Main extends React.Component {

    constructor(props){
        super(props);
        this.state = {
            selectedItem: {},
            openModal: false
        }
    }

    openModalAction = (el) => {
        this.setState({
            selectedItem: el,
            openModal: true
        })
    }

    closeModalAction = () => {
        this.setState({
            selectedItem: {},
            openModal: false
        })
    }


    render(){
        const { classes } = this.props;
        let productModel = this.props.store.products; // gettting products instance from Mobx Store
        })

        return (

            <React.Fragment>
                {/*Modal item*/}
                { this.state.openModal && // use && operator
                  <ModalItem item={this.state.selectedItem} /> // change to ModalItem, remove space and add .state
                }

              
                {/*Items for sale*/}

                <div>
                 <Typography variant="h3" align="center" gutterBottom> Items </Typography>
                   <Grid container spacing={3}>
                       {productModel.getAll().map((el, i) => (  //maybe getAll()
                        <Grid item xs={3} key={i}>
                         <Card>
                          <CardContent>
                           <Typography variant="h4">{el.title}</Typography>
                           <Typography variant="subtitle1">{el.price}</Typography>
                          </CardContent>
                          <CardActions>
                           <Button color="secondary" onClick={ () => this.openModalAction(el) }>Quick look</Button>
                           <Button color="primary">Add to cart</Button>
                          </CardActions>
                         </Card>
                        </Grid>
                       ))}
                   </Grid>
                </div>
                /*</div>*/ //remove this

            </React.Fragment>
        )
    }

}))

ModalItem:

const useStyles = {
    modal: {
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
    }
}
class ModalItem extends React.Component{

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

        return(
            <Card className={classes.modal}>
                <CardContent>
                    <Grid container>
                        <Grid item xs={6}>

                        </Grid>
                        <Grid item xs={6}>
                            <Typography variant="h3">{item.title}</Typography>
                            <Typography variant="subtitle1">{item.price}</Typography>
                            <Grid container item xs={12}>
                                <Grid item xs={6}>
                                    <TextField
                                    type="number"/>
                                </Grid>
                                <Grid item xs={6}>
                                    <Button color="primary">Add to cart</Button>
                                </Grid>
                            </Grid>
                            <Typography variant="subtitle2">Category</Typography>
                            <Button>Full review</Button>
                        </Grid>
                    </Grid>
                </CardContent>
            </Card>
        )
    }
}

ModalItem.propTypes = {
    item: PropType.object
}

export default  withStyles(useStyles)(ModalItem);