React - Can't find the leak, infinite state declaration suspected

ε祈祈猫儿з 提交于 2021-02-11 13:27:20

问题


I'm a complete beginner in React and I was pretty happy with my first app since I, maybe, have a memory leak ? My app is very laggy after entering value in the input, after click on the add button, at bottom right, and I suspect that I don't use 'useState' like I should ? I dunno, I've been searching for hours :( ...

Here's the app : https://n3g.gitlab.io/react-conso-energie/

Here's the code :

In the App.js (parent) :

import React, { useState } from 'react'
import firebase from './firebase'
import AddForm from './AddForm'
import ListingTable from './ListingExpansionPanels'
import moment from 'moment'
// MATERIAL UI
import { CssBaseline } from '@material-ui/core'
import Grid from '@material-ui/core/Grid'
import Snackbar from '@material-ui/core/Snackbar'
import MuiAlert from '@material-ui/lab/Alert'

import './styles.css'

export default function App () {
  // BDD
  const dbRef = firebase.database().ref('items')

  // LISTING DATA
  const [listingData, setListingData] = useState([{}])

  dbRef.once('value', (snapshot) => {
    const releves = snapshot.val()
    const listingData = []
    for (const [key, releve] of Object.entries(releves)) {
      listingData.push({
        key: key,
        month: releve.month,
        gaz: releve.gaz,
        electricite: releve.electricite,
        total: releve.total,
        submissionDate: releve.submissionDate
      })
    }
    const listingDataSorted = listingData.sort((a, b) => (a.submissionDate > b.submissionDate) ? 1 : -1)
    setListingData(listingDataSorted)
  })

  const lastItemIndex = listingData.length - 1

  // MONTHS
  const [selectedDate, handleDateChange] = useState(new Date())
  const dateFormat = moment(selectedDate).format('MMMM')

  // ELECTRICITÉ
  const constElec = { prix: 0.15356, abo: 117.56 }
  const [kw, setKw] = useState('')
  const diffElec = kw - listingData[lastItemIndex].electricite
  const resultatElec = Math.round((constElec.prix * diffElec + (constElec.abo / 12)) * 1e2) / 1e2

  // GAZ
  const constGaz = { prix: 0.0681, abo: 215.73, indice: 11.34 }
  const [m3, setm3] = useState('')
  const diffGaz = m3 - listingData[lastItemIndex].gaz
  const resultatGaz = Math.round((((constGaz.indice * diffGaz) * constGaz.prix) + (constGaz.abo / 12)) * 1e2) / 1e2

  // TOTAL
  const total = Math.round((resultatElec + resultatGaz) * 1e2) / 1e2

  // SUBMIT
  const handleSubmit = () => {
    const releve = {
      submissionDate: moment(selectedDate).unix(),
      month: dateFormat,
      gaz: m3,
      electricite: kw,
      total: total
    }
    dbRef.push(releve)
    setOpenSnack(true)
    setm3('')
    setKw('')
  }

  // DELETE
  const handleDelete = key => {
    dbRef.child(key).remove()
  }

  // SNACKBAR
  function Alert (props) {
    return <MuiAlert elevation={6} variant='filled' {...props} />
  }
  const [openSnack, setOpenSnack] = React.useState(false)
  const handleClose = (event, reason) => {
    if (reason === 'clickaway') {
      return
    }
    setOpenSnack(false)
  }

  return (
    <>
      <CssBaseline />
      <div className='App'>
        <Grid container justify='center' spacing={2}>
          <Grid item xs={12}>
            <h1>Conso Energie</h1>
            <AddForm m3={m3} setm3={setm3} kw={kw} setKw={setKw} selectedDate={selectedDate} handleDateChange={handleDateChange} handleSubmit={handleSubmit} />
          </Grid>
          <Grid item xs={12}>
            <ListingTable listingData={listingData} handleDelete={handleDelete} />
          </Grid>
        </Grid>
        <Snackbar open={openSnack} autoHideDuration={3500} onClose={handleClose}>
          <Alert onClose={handleClose} severity='success'>
            Sauvegardé
          </Alert>
        </Snackbar>
      </div>
    </>
  )
}

In the AddForm.js (child - I'm using Material UI) :

import React from 'react'
import TextField from '@material-ui/core/TextField'
import InputAdornment from '@material-ui/core/InputAdornment'
import Button from '@material-ui/core/Button'
import CloudUploadIcon from '@material-ui/icons/CloudUpload'
import { MuiPickersUtilsProvider, DatePicker } from '@material-ui/pickers'
import MomentUtils from '@date-io/moment'
import moment from 'moment'
import 'moment/locale/fr'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogTitle from '@material-ui/core/DialogTitle'
import Fab from '@material-ui/core/Fab'
import AddIcon from '@material-ui/icons/Add'

export default function AddForm ({ m3, setm3, kw, setKw, handleSubmit, selectedDate, handleDateChange }) {
  const handleUpdateGaz = function (event) {
    setm3(Number(event.target.value))
  }
  const handleUpdateKw = function (event) {
    setKw(Number(event.target.value))
  }
  moment.locale('fr')

  const [open, setOpen] = React.useState(false)
  const handleClickOpenAddDialog = () => {
    setOpen(true)
  }
  const handleCloseAddDialog = () => {
    setOpen(false)
  }

  return (
    <>
      <div>
        <Fab className='fab-btn-add' color='primary' aria-label='add' onClick={handleClickOpenAddDialog}>
          <AddIcon />
        </Fab>
        <Dialog
          open={open}
          onClose={handleCloseAddDialog}
          aria-labelledby='alert-dialog-title'
          aria-describedby='alert-dialog-description'
        >
          <DialogTitle id='alert-dialog-title'>Entrer les valeurs</DialogTitle>
          <DialogContent>
            <form className='addform' noValidate autoComplete='off'>
              <MuiPickersUtilsProvider utils={MomentUtils}>
                <DatePicker
                  inputVariant='outlined'
                  value={selectedDate}
                  onChange={handleDateChange}
                  label='Mois'
                  format='MMMM Y'
                  views={['month']}
                  minDate={new Date('2020-01-01')}
                  maxDate={new Date('2020-12-31')}
                />
              </MuiPickersUtilsProvider>
              <TextField
                label='Electricité'
                variant='outlined'
                type='number'
                InputProps={{
                  endAdornment: <InputAdornment position='end'>kW</InputAdornment>
                }}
                value={kw}
                onChange={handleUpdateKw}
              />
              <TextField
                label='Gaz'
                variant='outlined'
                type='number'
                InputProps={{
                  endAdornment: <InputAdornment position='end'>m3</InputAdornment>
                }}
                value={m3}
                onChange={handleUpdateGaz}
              />
              <Button
                className='btn-submit'
                size='large'
                variant='contained'
                color='primary'
                startIcon={<CloudUploadIcon />}
                onClick={handleSubmit}
              >
                Confirmer
              </Button>
            </form>
          </DialogContent>
          <DialogActions>
            <Button onClick={handleCloseAddDialog} color='primary' autoFocus>
              Retour
            </Button>
          </DialogActions>
        </Dialog>
      </div>
    </>
  )
}

Pretty sure it's unrelated but here's the ListingExpansionPanel.js

import React from 'react'
import ExpansionPanel from '@material-ui/core/ExpansionPanel'
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'
import Typography from '@material-ui/core/Typography'
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'
import Icon from '@material-ui/core/Icon'
import Grid from '@material-ui/core/Grid'
import Button from '@material-ui/core/Button'
import Chip from '@material-ui/core/Chip'
import SwipeableViews from 'react-swipeable-views'

export default function ListingTable ({ listingData, handleDelete }) {
  const dataRow = listingData.map((data, key) => (
    <ExpansionPanel key={key} className='relevePanel'>
      <ExpansionPanelSummary
        expandIcon={<ExpandMoreIcon />}
        aria-controls={key}
        id={key}
      >
        <Typography>
          <span>
            <Icon style={{ marginRight: 15 }}>calendar_today</Icon>
            {data.month}<b>{data.total ? ' : ' + data.total + ' €' : ''}</b>
          </span>
        </Typography>
      </ExpansionPanelSummary>
      <ExpansionPanelDetails>
        <SwipeableViews>
          <Typography className='expansion-detail'>
            <Grid container>
              <Grid item xs={12}>
                <b style={{ color: '#cacaca' }}>2020</b>
              </Grid>
              <Grid item xs>
                <Icon>power</Icon>
                <span>{data.electricite} <small>Kwh</small></span>
                <div>
                  <Chip className='plus' size='small' label='+3,4%' />
                </div>
              </Grid>
              <Grid item xs>
                <Icon>whatshot</Icon>
                <span>{data.gaz} <small>m<sup>3</sup></small></span>
                <div>
                  <Chip className='moins' size='small' label='-5,2%' />
                </div>
              </Grid>
              <Grid item xs={12}>
                <Button
                  className='btnRemove'
                  style={{ marginTop: 15 }}
                  size='small'
                  color='secondary'
                  onClick={() => handleDelete(data.key)}
                >
                  Supprimer
                </Button>
              </Grid>
            </Grid>
          </Typography>
          <Typography className='expansion-detail'>
            <Grid container>
              <Grid item xs={12}>
                <b style={{ color: '#cacaca' }}>2019</b>
              </Grid>
              <Grid item xs>
                <Icon>power</Icon>
                <span>{data.electricite} <small>Kwh</small></span>
                <div>
                  <Chip className='plus' size='small' label='+3,4%' />
                </div>
              </Grid>
              <Grid item xs>
                <Icon>whatshot</Icon>
                <span>{data.gaz} <small>m<sup>3</sup></small></span>
                <div>
                  <Chip className='moins' size='small' label='-5,2%' />
                </div>
              </Grid>
              <Grid item xs={12}>
                <Button
                  className='btnRemove'
                  style={{ marginTop: 15 }}
                  size='small'
                  color='secondary'
                  onClick={() => handleDelete(data.key)}
                >
                  Supprimer
                </Button>
              </Grid>
            </Grid>
          </Typography>
        </SwipeableViews>
      </ExpansionPanelDetails>
    </ExpansionPanel>
  ))

  return (
    <>
      {dataRow}
    </>
  )
}

Thank you A LOT for your help, if someone see something. I continue to search..

Thanks.

Update : Added the whole code for this 2 files

Update 2 : When I disable the firebase link, it's ok ! So I'll investigate this way..


回答1:


This won't solve your problem but one thing that will use less memory is not creating an anonymous function, but replacing it with a reference in child components.

In the AddForm.js :

// pass the reference to changeKw instead of creating an anonymous function:
<TextField
    value={kw}
    onChange={changeKw} // e will be passed automatically
/>

In the App.js (parent) :

const changeKw = e => {
    console.log(e.target.value) // e gets passed
    setKw(e.target.value)
}


来源:https://stackoverflow.com/questions/60420872/react-cant-find-the-leak-infinite-state-declaration-suspected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!