反应-找不到泄漏,怀疑有无限状态声明 [英] React - Can't find the leak, infinite state declaration suspected
问题描述
我是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屋!