Where to place a Modal "const" of the Material UI inside a Class in Reactjs?

Asked

Viewed 41 times

0

I have a problem of not knowing where to put the const "const [open, setOpen] = React.useState(false);" of a Modal from the Material UI, within my Generatereport class.

When I put " const [open, setOpen] = React.useState(false);" inside the render, the error " Error: Invalid hook call. Hooks can only be called Inside of the body of a Function Component".

My code is like this:

import React, { Component } from 'react';

//modal:
import Modal from '@material-ui/core/Modal';
import Backdrop from '@material-ui/core/Backdrop';
import Fade from '@material-ui/core/Fade';

import { connect } from 'react-redux';
import firebase from 'firebase/app';
import _ from 'lodash';
import { Link } from 'react-router-dom';
import { Form, Select, DatePicker, Popover } from 'antd';
import { LoadingOutlined, DownloadOutlined } from '@ant-design/icons';
import Button from '@material-ui/core/Button';
import { Container, ActionsForm, Loading } from './styles';

import ReactToExcel from 'react-html-table-to-excel';

import { changePage } from '../../../store/modules/user/actions';
import {
    getAllEstablishmentsRequest,
    getLocationsRequest,
} from '../../../store/modules/establishment/actions';

const { RangePicker } = DatePicker;

const configValidation = {
    rules: [
        {
            type: 'array',
            required: true,
            message: 'Esse campo é obrigatório!',
        },
    ],
};

const formRef = React.createRef();

// const rangeValue = fieldsValue['range-picker'];

class GenerateReport extends Component {

    state = {
        file: null,
        update: false,
        searchText: '',
        searchedColumn: '',
        establishment: [],
        loading: false,
    };

    componentDidMount() {
        this.setState({ loading: true });
        // const { state } = this.props.location;

        this.props.getLocationsRequest();
        this.props.changePage(
            'relatorio',
            'GERADOR DE RELATÓRIOS',
            '',
            ''
        );

        // this.props.getAllEstablishmentsRequest(this.props.profile)

        firebase
            .database()
            .ref('/estabelecimentos_pedidos')
            .once('value')
            .then(snapshot => {
                if (!this.props.profile.franqueado) {
                    this.setState({ establishment: _.values(snapshot.val()), loading: false });
                } else {
                    const establishment = _.values(snapshot.val())
                        .map(usuario => {
                            if (usuario.email === this.props.profile.email) return;
                            if (usuario.localizacao === this.props.profile.localizacao) {
                                return usuario;
                            }
                        })
                        .filter(establishment => establishment !== undefined);
                    this.setState({ establishment, loading: false });
                }
            })
            .catch(err => {
                this.setState({ loading: false });
            });
    }


    onFinish = async values => {
        let localizacaoRef = '';

        let fieldsValue = 0;

        this.props.locations.map(location => {
            if (location.nome === values.localizacao) {
                localizacaoRef = location.uid;
            }
        });

        this.props.getAllEstablishmentsRequest({
            estabeReference: values.estabeReference,
            nome: values.nome,
            localizacao: values.localizacao,
            localizacaoRef,
            rangeValue: values.pedidos,
        });
    };

    onChange = e => {
        this.setState({ file: e.target.files[0] });
    };

    handleSearch = (selectedKeys, confirm, dataIndex) => {
        confirm();
        this.setState({
            searchText: selectedKeys[0],
            searchedColumn: dataIndex,
        });
    };

    render() {
        const {
            loading,
            locations,
            loadingLocations,
            loadingEstablishments,
            establishments,

        } = this.props;


        const [open, setOpen] = React.useState(false);

        //modal:
        const handleOpen = () => {
            setOpen(true);
        };

        const handleClose = () => {
            setOpen(false);
        };

        return (
            <Container>

                <h1>Gerar Relatório Específico</h1>

                <Form ref={formRef} onFinish={this.onFinish}>

                    <Popover
                        content={<strong>Período para o relatório</strong>}
                        placement="right"
                        trigger="hover"
                    >
                        <Form.Item name="range-picker" {...configValidation}>
                            <RangePicker
                                format="DD/MM/YYYY"
                                style={{ width: '100%' }}
                            />
                        </Form.Item>
                    </Popover>

                    <Popover
                        content={<strong>Selecione a(s) Cidade(s)</strong>}
                        placement="right"
                        trigger="hover"
                    >
                        <Form.Item name="locations">
                            <Select
                                showSearch
                                mode="multiple"
                                optionFilterProp="children"
                                placeholder="Selecione a(s) Cidade(s)"
                                loading={loadingLocations}
                                filterOption={(input, option) =>
                                    option.children.toLowerCase().indexOf(input.toLowerCase()) >=
                                    0
                                }
                            >
                                <Select.Option value="" disabled>
                                    Selecione a(s) Cidade(s)
                                </Select.Option>
                                {locations.map(location => (
                                    <Select.Option
                                        key={location.nome}
                                        value={location.nome}
                                    >
                                        {location.nome}
                                    </Select.Option>
                                ))}
                            </Select>
                        </Form.Item>
                    </Popover>

                    <Popover
                        content={<strong>Selecione o(s) Estabelecimento(s)</strong>}
                        placement="right"
                        trigger="hover"
                    >
                        <Form.Item name="establishments">
                            <Select
                                showSearch
                                mode="multiple"
                                optionFilterProp="children"
                                placeholder="Selecione o(s) Estabelecimento(s)"
                                loading={loadingEstablishments}
                                filterOption={(input, option) =>
                                    option.children.toLowerCase().indexOf(input.toLowerCase()) >=
                                    0
                                }
                            >
                                <Select.Option value="" disabled>
                                    Selecione o(s) Estabelecimento(s)
                                </Select.Option>
                                {establishments.map(establishment => (
                                    <Select.Option
                                        key={establishment.nome}
                                        value={establishment.nome}
                                    >
                                        {establishment.nome}
                                    </Select.Option>
                                ))}
                            </Select>
                        </Form.Item>
                    </Popover>

                    {loading ? (

                        <Loading>
                            <LoadingOutlined />
                        </Loading>
                    ) : (

                            <Form.Item>


                                <ActionsForm>

                                    <button type="button" onClick={handleOpen}>
                                        react-transition-group
                        </button>
                                    <Modal
                                        aria-labelledby="transition-modal-title"
                                        aria-describedby="transition-modal-description"
                                        // className={classes.modal}
                                        open={open}
                                        onClose={handleClose}
                                        closeAfterTransition
                                        BackdropComponent={Backdrop}
                                        BackdropProps={{
                                            timeout: 500,
                                        }}
                                    >
                    
                                        <Fade in={open}>
                                            <div
                                            // className={classes.paper}
                                            >
                                                <h2 id="transition-modal-title">Transition modal</h2>
                                                <p id="transition-modal-description">react-transition-group animates me.</p>
                                            </div>
                                        </Fade>
                                    </Modal>

                                    <Button
                                        type="submit"
                                        disabled={loading}
                                        onClick={(_handleOpenTable) => window.open("", "_self")}
                                    >
                                        Gerar
                                </Button>

                                    {/* <button type="button" onClick={{}}>
                                        Open Modal</button> */}

                                    <ReactToExcel
                                        table="table-to-xls"
                                        filename={`Relatório-QPreço`}
                                        sheet="Tabela 1"
                                        buttonText="Exportar para Excel"
                                    >

                                        Teste
                                    </ ReactToExcel>

                                    <Link to="/reports">
                                        Voltar para Relatórios
                                </Link>
                                </ActionsForm>
                            </Form.Item>
                        )}

                </Form>

                <table id="table-to-xls">

                </table>
            </Container>

        );
    }
}

const mapStateToProps = state => ({
    loading: state.establishment.loading,
    locations: state.establishment.locations,
    loadingEstablishments: state.establishment.loading,
    establishments: state.establishment.establishments,
});

const mapDispatchToProps = {
    changePage,
    getLocationsRequest,
    getAllEstablishmentsRequest,
};

export default connect(mapStateToProps, mapDispatchToProps)(GenerateReport);

  • 1

    You cannot use the Hooks within a class component, as you say in the error you can only use Hooks within a functional component. I believe you can include this information within your state.

1 answer

2


Dude.. you can’t use useState inside the render, you must pass that information before the render.. inside a constructor as the documentation says... Example:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

https://pt-br.reactjs.org/docs/hooks-state.html

Edit1: Applying this to your code you would first change your state

state = {
        file: null,
        update: false,
        searchText: '',
        searchedColumn: '',
        establishment: [],
        loading: false,
        open: false
    };

Then remove from inside render code

const [open, setOpen] = React.useState(false);

        modal:
        const handleOpen = () => {
            setOpen(true);
        };

        const handleClose = () => {
            setOpen(false);
        };

And would add it just below the handleSearch() function so:

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

That would probably solve your problem :)

  • 1

    Great. I appreciate it. And where and how I would put it in my code?

  • @Roberlancarvalho updated the answer to make it easier for you to understand

Browser other questions tagged

You are not signed in. Login or sign up in order to post.