反应-找不到泄漏,怀疑有无限状态声明 [英] React - Can't find the leak, infinite state declaration suspected

查看:51
本文介绍了反应-找不到泄漏,怀疑有无限状态声明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是React的一个完整的初学者,我对自己的第一个应用程序感到非常满意,因为我可能会发生内存泄漏?在输入内容中输入值之后,单击右下角的添加按钮后,我的应用程序非常滞后,我怀疑我没有像应该使用的那样使用'useState'吗?我不知道,我一直在找几个小时:( ...

以下是该应用程序: https://n3g.gitlab.io/react-conso-能量/

这是代码:

在App.js(父级)中:

  import React,{useState} from'react'从"./firebase"导入firebase从"./AddForm"导入AddForm从'./ListingExpansionPanels'导入ListingTable从时刻"导入时刻//材质界面从'@ material-ui/core'导入{CssBaseline}从'@ material-ui/core/Grid'导入网格从'@ material-ui/core/Snackbar'导入Snackbar从'@ material-ui/lab/Alert'导入MuiAlert导入'./styles.css'导出默认功能App(){//BDDconst dbRef = firebase.database().ref('items')//清单数据const [listingData, setListingData] = useState([{}])dbRef.once('value',(snapshot)=> {const releves = snapshot.val()const listingData = []for(Object.entries(releves)的(const [key,releve]]){listingData.push({钥匙:钥匙,month:releve.month,gaz:releve.gaz,电工:releve.electricite,总计:releve.total,SubmittingDate:releve.submissionDate})}const listingDataSorted = listingData.sort((a,b)=>(a.submissionDate> b.submissionDate)?1:-1)setListingData(listingDataSorted)})const lastItemIndex = listingData.length-1//月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] .electriciteconst resultatElec = Math.round(((constElec.prix * diffElec +(constElec.abo/12))* 1e2)/1e2//GAZconst constGaz = {prix:0.0681,abo:215.73,indice:11.34}const [m3,setm3] = useState('')const diffGaz = m3-listingData [lastItemIndex] .gazconst resultatGaz = Math.round((((((constGaz.indice * diffGaz)* constGaz.prix)+(constGaz.abo/12))* 1e2)/1e2//全部的const total = Math.round((resultatElec + resultatGaz)* 1e2)/1e2//提交const handleSubmit =()=>{常量相关 = {SubmittingDate:时刻(selectedDate).unix(),月:dateFormat,天然气:m3,电工:千瓦,总计:总计}dbRef.push(releve)setOpenSnack(真)setm3('')setKw('')}//删除const handleDelete =键=>{dbRef.child(key).remove()}//小吃店功能提醒(道具){返回< MuiAlert海拔= {6}变量=已填充" {... props}/>}const [openSnack,setOpenSnack] = React.useState(false)const handleClose =(事件,原因)=>{if(reason ==='clickaway'){返回}setOpenSnack(假)}返回 (<>< CssBaseline/>< div className ='App'><网格容器对齐='中心'间隔= {2}><网格项xs = {12}>< h1> Conso Energie</h1>< AddForm m3 = {m3} setm3 = {setm3} kw = {kw} setKw = {setKw} selectedDate = {selectedDate} handleDateChange = {handleDateChange} handleSubmit = {handleSubmit}/></Grid><网格项xs = {12}>< ListingTable listingData = {listingData} handleDelete = {handleDelete}/></Grid></Grid>< Snackbar open = {openSnack} autoHideDuration = {3500} onClose = {handleClose}>< Alert onClose = {handleClose}严重性='成功'>Sauvegardé</警报></小吃店></div></>)} 

在AddForm.js中(子级-我正在使用Material UI):

 从'react'导入React从'@ material-ui/core/TextField'导入TextField从'@ material-ui/core/InputAdornment'导入InputAdornment从'@ material-ui/core/Button'导入Button从'@ material-ui/icons/CloudUpload'导入CloudUploadIcon从'@ material-ui/pickers'导入{MuiPickersUtilsProvider,DatePicker}从'@ date-io/moment'导入MomentUtils从时刻"导入时刻导入'moment/locale/fr'从'@ material-ui/core/Dialog'导入对话框从'@ material-ui/core/DialogActions'导入DialogActions从'@ material-ui/core/DialogContent'导入DialogContent从'@ material-ui/core/DialogTitle'导入DialogTitle从'@ material-ui/core/Fab'导入Fab从'@ material-ui/icons/Add'导入AddIcon导出默认函数AddForm({m3,setm3,kw,setKw,handleSubmit,selectedDate,handleDateChange}){const handleUpdateGaz =函数(事件){setm3(Number(event.target.value))}const handleUpdateKw =函数(事件){setKw(Number(event.target.value))}moment.locale('fr')const [open,setOpen] = React.useState(false)const handleClickOpenAddDialog =()=>{setOpen(真)}const handleCloseAddDialog =()=>{setOpen(假)}返回 (<>< div>< Fab className ='fab-btn-add'color ='primary'aria-label ='add'onClick = {handleClickOpenAddDialog}>< AddIcon/></Fab><对话打开= {打开}onClose = {handleCloseAddDialog}aria-labelledby ='alert-dialog-title'咏叹调所描述=警报对话描述">< DialogTitle id ='alert-dialog-title'>入口价</DialogTitle>< DialogContent>< form className ='addform'noValidate autoComplete ='off'>< MuiPickersUtilsProvider utils = {MomentUtils}>< DatePickerinputVariant ='已概述'值= {selectedDate}onChange = {handleDateChange}label ='Mois'格式='MMMM Y'views = {['month']}minDate = {新日期('2020-01-01')}maxDate = {新日期('2020-12-31')}/></MuiPickersUtilsProvider>< TextFieldlabel ='Electricité'变体=已概述"类型='数字'InputProps = {{endAdornment:< InputAdornment position ='end'> kW</InputAdornment>}}值= {kw}onChange = {handleUpdateKw}/>< TextFieldlabel ='Gaz'变体=已概述"类型='数字'InputProps = {{endAdornment:< InputAdornment position ='end'> m3</InputAdornment>}}值= {m3}onChange = {handleUpdateGaz}/><按钮className ='btn-submit'size ='大'variant ='包含'color ='primary'startIcon = {< CloudUploadIcon/>}onClick = {handleSubmit}>确认者</按钮></form></DialogContent>< DialogActions><按钮onClick = {handleCloseAddDialog} color ='primary'autoFocus>重走</按钮></DialogActions></Dialog></div></>)} 

可以肯定它是不相关的,但这是ListingExpansionPanel.js

 从'react'导入React从'@ material-ui/core/ExpansionPanel'导入ExpansionPanel从'@ material-ui/core/ExpansionPanelSummary'导入ExpansionPanelSummary从'@ material-ui/core/ExpansionPanelDetails'导入ExpansionPanelDetails从'@ material-ui/core/Typography'导入版式从'@ material-ui/icons/ExpandMore'导入ExpandMoreIcon从'@ material-ui/core/Icon'导入图标从'@ material-ui/core/Grid'导入网格从'@ material-ui/core/Button'导入Button从'@ material-ui/core/Chip'导入芯片从'react-swipeable-views'导入SwipeableViews导出默认函数ListingTable({listingData,handleDelete}){const dataRow = listingData.map((data,key)=>(< ExpansionPanel key = {key} className ='relevePanel'>< ExpansionPanelSummaryexpandIcon={}aria-controls = {key}id = {key}><印刷术>< span><图标样式= {{marginRight:15}}> calendar_today</Icon>{data.month}< b> {data.total吗?':'+ data.total +'€':''}</b></span></Typography></ExpansionPanelSummary>< ExpansionPanelDetails>< SwipeableViews>< Typography className ='扩展细节'><网格容器><网格项xs = {12}><b style={{ color: '#cacaca' }}>2020</b></Grid><网格项xs>< Icon>功率</Icon>< span> {data.electricite}< small Kwh< small</span>< div><芯片className ='plus'size ='small'label ='+ 3,4%'/></div></Grid><网格项目 xs><图标>快照</图标>< span> {data.gaz}< small< m< sup> 3</sup</small</span>< div><芯片className ='moins'size ='small'label ='-5,2%'/></div></Grid><网格项xs = {12}><按钮className ='btnRemove'样式= {{marginTop:15}}size ='small'color ='secondary'onClick = {()=>handleDelete(data.key)}>补充剂</按钮></Grid></Grid></Typography>< Typography className ='扩展细节'><网格容器><网格项xs = {12}>< b style = {{color:'#cacaca'}}> 2019</b></Grid><网格项xs>< Icon>功率</Icon><span>{data.electricite} <small>Kwh</small></span>< div><芯片className ='plus'size ='small'label ='+ 3,4%'/></div></Grid><网格项xs><图标>快照</图标>< span> {data.gaz}< small< m< sup> 3</sup</small</span>< div><芯片className ='moins'size ='small'label ='-5,2%'/></div></Grid><网格项xs = {12}><按钮className ='btnRemove'style={{ marginTop: 15 }}size ='small'color ='secondary'onClick = {()=>handleDelete(data.key)}>补充剂</按钮></Grid></Grid></Typography></SwipeableViews></ExpansionPanelDetails></ExpansionPanel>))返回 (<>{dataRow}</>)} 

如果有人看到了东西,请多多帮助.我继续搜索..

谢谢.

更新:添加了这2个文件的完整代码

更新2:当我禁用Firebase链接时,就可以了!因此,我将以这种方式进行调查.

解决方案

这不会解决您的问题,但是会占用更少内存的一件事不是创建匿名函数,而是将其替换为子组件中的引用./p>

在AddForm.js中:

 //将引用传递给changeKw而不是创建匿名函数:< TextField值= {kw}onChange = {changeKw}//e将自动传递/> 

在App.js(父级)中:

  const changeKw = e =>{console.log(e.target.value)//e被传递setKw(e.target.value)} 

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..

解决方案

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)
}

这篇关于反应-找不到泄漏,怀疑有无限状态声明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆