Я новичок в React, и я был очень доволен своим первым приложением, так как у меня, может быть, утечка памяти? Мое приложение очень запаздывает после ввода значения на входе, после нажатия на кнопку «Добавить» в правом нижнем углу, и я подозреваю, что я не использую «useState», как следует? Я не знаю, я искал часы :( ...
Вот приложение: https://n3g.gitlab.io/react-conso-energie/
Вот код:
В приложении. js (родительский):
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>
</>
)
}
В AddForm. js (дочерний - я использую интерфейс материалов):
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>
</>
)
}
Уверен, что это не имеет отношения, но вот 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}
</>
)
}
Большое спасибо за вашу помощь, если кто-то что-то увидит. Я продолжаю искать ..
Спасибо.
Обновление: добавлен весь код для этих 2 файлов
Обновление 2: Когда я отключаю ссылку на firebase, все нормально! Поэтому я буду исследовать этот способ ..