I have few Card component from material UI, each of them contain an EDIT button and there is a handler available for it, they are being added dynamically using Map traversing (In example, i have just hard coded two of them).
Now, i am trying to make the card editable in button click but not able to find out how to get to know from which Card, event is triggered and then make "Typography" of that editable to 'TextField'.
<CardContent>
<Typography>ID: '1'</Typography>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</CardContent>
<CardActions>
<Button size="small" onClick={click}>
Edit
</Button>
</CardActions>
<CardContent>
Here is my codeSandbox example
CodeSandbox
The usual solution is to have the card pass back some identifying information or an object that you've passed it, since there's very little you can do with the React element.
If you want the DOM element, it's the currentTarget property of the event object that your click function receives.
Here's a simple example showing both with stand-ins for Card and its parent, in this case the Card component returns the id you pass it as a second argument to the click function:
"use strict";
const cards = Array.from(Array(5), (_, index) => ({
id: index + 1,
value: `Card ${index + 1}`
}));
function Parent() {
const click = (evt, id) => {
console.log(`evt.currentTarget.tagName = ${evt.currentTarget.tagName}, id = ${id}`);
};
return cards.map(({id, value}) =>
<Card
key={id}
value={value}
onClick={evt => click(evt, id)}
/>
);
}
function Card({value, onClick}) {
return <div onClick={onClick}>{value}</div>;
}
ReactDOM.render(<Parent />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
import React, { useRef } from "react";
import { makeStyles } from "#material-ui/core/styles";
import Card from "#material-ui/core/Card";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import Button from "#material-ui/core/Button";
import Typography from "#material-ui/core/Typography";
const useStyles = makeStyles({
root: {
minWidth: 275
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)"
},
title: {
fontSize: 14
},
pos: {
marginBottom: 12
}
});
export default function OutlinedCard() {
const refs = useRef([]);
const classes = useStyles();
const click = (event) => {
const { currentTarget: { id = "" } = {} } = event;
const clickedCard = refs.current[id]; // This is the card whose button got clicked
console.log(clickedCard);
};
const createRefs = (id, node) => (refs.current[id] = node);
return (
<Card className={classes.root} variant="outlined">
<CardContent ref={(node) => {createRefs('card_1', node)}}>
<Typography>ID: '1'</Typography>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</CardContent>
<CardActions>
<Button size="small" id="card_1" onClick={click}>
Edit
</Button>
</CardActions>
<CardContent ref={(node) => {createRefs('card_2', node)}}>
<Typography>ID: '2'</Typography>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography>Name: 'RAAM'</Typography>
<Typography>Blood group: 'AB+'</Typography>
<Typography>"Patient Ram is having bloodgroup AB+"</Typography>
</CardContent>
<CardActions>
<Button size="small" id="card_2" onClick={click}>
Edit
</Button>
</CardActions>
</Card>
);
}
Related
I'm trying to use Slider/Select to get user query parameters, which will make further changes to the URL (through handleChange) and make api calls through fetch hooks.
However, when I change the Slider value from 1 to 0.1, nothing happens, but if I change the slider value again to 0.1 to 0.2, it will return me the result of 0.1 ( therefore lagging by 1 click). Similar behavior is observed with the Select value.
Website here:https://thisorthatstockfrontend.herokuapp.com/rankStockSharpeFiltered
I don't have form control but after trying form control it didn't seem to fix the issue. I really do not want to have a submit button, any help is appreciated!
import React from 'react'
import { NavLink } from 'react-router-dom'
import { Button,InputLabel } from '#mui/material'
import { Typography,MenuItem } from '#mui/material'
import { DataGrid } from '#mui/x-data-grid'
import Slider from '#mui/material/Slider';
import { useEffect } from 'react'
import {FormControl} from '#mui/material';
import { useState } from 'react'
import { useFetch } from '../hooks/useFetch';
import { useForm,Controller } from "react-hook-form";
import Select,{SelectChangeEvent} from '#mui/material/Select';
import Grid from '#mui/material/Grid'
import { Box } from '#mui/system';
export default function StockListedFiltered()
{
const [values, setValues] = useState(
{
sharpeYear1: 1,
sharpeYear2: 5,
sharperatio1Cutoff: 1,
sharperatio2Cutoff: 1,
}
);
const [url,seturl]=useState('https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' + values.sharpeYear1+'&LongYearNum='+values.sharpeYear2+'&sharpeRatio1='+values.sharperatio1Cutoff+'&sharpeRatio2='+values.sharperatio2Cutoff)
const handleChange = (propertyName) => (event) => {
console.log('hello')
event.preventDefault();
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
console.log('end')
console.log(values)
seturl('https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' + values.sharpeYear1+'&LongYearNum='+values.sharpeYear2+'&sharpeRatio1='+values.sharperatio1Cutoff+'&sharpeRatio2='+values.sharperatio2Cutoff)
console.log(url)
};
const{data:stockPerformance ,isPending,error}=useFetch(url)
const columns=[
{field:'stockName', headerName:'ticker',width:200 },
{field:'years', headerName:'years' ,width:200},
{field:'SharpeRatio', headerName:'sharpe ratio',width:200},
{field:'AnnualReturn', headerName:'annual return',width:200 },
{field:'AnnualVolatility', headerName:'annual volatility',width:200 }
];
return (
<div>
<h2 style={{paddingTop:'3rem',textAlign:'center',paddingBottom:'2rem'}}> Filtered Stocks Ranked </h2>
<NavLink to="/rankStockSharpe">
<Button>
<Typography>All stock </Typography>
</Button>
</NavLink>
<NavLink to="/rankStockSharpeFiltered">
<Button>
<Typography>Filtered </Typography>
</Button>
</NavLink>
<Grid container style={{paddingTop:'2rem',textAlign:'center'}}>
<Grid item xs={2}></Grid>
<Grid item xs={4} style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
<Grid item xs={6}>
<Typography>
Years of Data
</Typography>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<Select
defaultValue={1}
labelId="sharpeYear1"
id="sharpeYear1-select"
value={values.sharpeYear1}
label="Year"
onChange={handleChange("sharpeYear1")}
>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={6}>
<Box sx={{ width: '80%' }}>
<Typography>
Sharpe Ratio cut off
</Typography>
<Slider
defaultValue={1}
value={values.sharperatio1Cutoff}
onChange={ handleChange("sharperatio1Cutoff")}
step={0.05}
valueLabelDisplay="auto"
min={0}
max={2}
/>
</Box>
</Grid>
</Grid >
<Grid item xs={4} style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
<Grid item xs={6}>
<Typography>
Years of Data
</Typography>
<Select
defaultValue={5}
labelId="sharpeYear2"
id="sharpeYear2-select"
value={values.sharpeYear2}
label="Year"
onChange={handleChange("sharpeYear2")}
>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
</Select>
</Grid>
<Grid item xs={6}>
<Box sx={{ width: '80%' }}>
<Typography>
Sharpe Ratio cut off
</Typography>
<Slider
defaultValue={1}
value={values.sharperatio2Cutoff}
onChange={handleChange("sharperatio2Cutoff")}
step={0.05}
valueLabelDisplay="auto"
min={0}
max={2}
/>
</Box>
</Grid>
</Grid>
</Grid>
<div style={{display:'flex',alignItems:'center',justifyContent:'center' }}>
{isPending&&<div>Loading Data...</div>}
{error &&<div>"This is awkard..."{error}</div>}
{!isPending && stockPerformance&&
<div style={{height:500,width:'70%'}}>
<DataGrid
rows={stockPerformance}
columns={columns}
></DataGrid>
</div>
}
</div>
</div>
)
}
React useState is asynchronous, so updating state & then accessing it immediately in next line will not work. Updated state is only available on the next render cycle.
The below will not console log the updated state. Same for setUrl.
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
console.log('end')
console.log(values) // state is not yet updated
If you want to perform an action on state update, you need to use the useEffect hook, much like using componentDidUpdate in class components since the setter returned by useState doesn't have a callback pattern
useEffect(() => {
// action on update of values
console.log(values) // updated state is available here
}, [values]);
You can clone the values state, make your changes by mutating and update your state. Then use the modified object to calculate the url so it has the new values.
const handleChange = (propertyName) => (event) => {
event.preventDefault();
const newValues = { ...values };
newValues[propertyName] = event.target.value;
setValues(newValues);
seturl(
'https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' +
newValues.sharpeYear1 +
'&LongYearNum=' +
newValues.sharpeYear2 +
'&sharpeRatio1=' +
newValues.sharperatio1Cutoff +
'&sharpeRatio2=' +
newValues.sharperatio2Cutoff
);
};
Or even better, calculate url in a second time (not directly in your handler), plus it doesn't have to be in the state.
const handleChange = (propertyName) => (event) => {
event.preventDefault();
const newValues = { ...values };
newValues[propertyName] = event.target.value;
setValues(newValues);
};
const url = useMemo(() => {
return (
'https://thisorthatstock.herokuapp.com/multipleStockPerformanceFilteredByYear?shortYearNum=' +
values.sharpeYear1 +
'&LongYearNum=' +
values.sharpeYear2 +
'&sharpeRatio1=' +
values.sharperatio1Cutoff +
'&sharpeRatio2=' +
values.sharperatio2Cutoff
);
}, [values]);
By the way, event could be null in this callback, destructure it so it's assigned to a variable or use event.persist().
setValues((values) => ({
...values,
[propertyName]: event.target.value
}));
Problem is in this code:
import React from 'react';
import { Card, CardActions, CardContent, CardMedia, Button, Typography, ButtonBase } from '#material-ui/core/';
import DeleteIcon from '#material-ui/icons/Delete';
import MoreHorizIcon from '#material-ui/icons/MoreHoriz';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { deleteBook } from '../../../../actions/books';
import useStyles from "./styles";
const Book = (book, setCurrentId) => {
const dispatch = useDispatch();
const classes = useStyles();
const user = JSON.parse(localStorage.getItem('profile'));
const history = useHistory();
console.log(book);
const openBook = (e) => {
history.push(`/books/${book._id}`);
};
return (
<Card className={classes.card} raised elevation={6}>
<ButtonBase
component="span"
name="test"
className={classes.cardAction}
onClick={openBook}
>
<CardMedia className={classes.media} image={book.slika || 'https://user-images.githubusercontent.com/194400/49531010-48dad180-f8b1-11e8-8d89-1e61320e1d82.png'} title={book.ime_knjige} />
{(user!= null && user.result.admin_stranice === true) && (
<div className={classes.overlay2} name="edit">
<Button
onClick={(e) => {
e.stopPropagation();
setCurrentId(book._id);
}}
style={{ color: 'white' }}
size="small"
>
<MoreHorizIcon fontSize="default" />
</Button>
</div>
)}
<Typography className={classes.title} gutterBottom variant="h5" component="h2">{book.ime_knjige}</Typography>
<Typography className={classes.title} gutterBottom variant="h5" component="h2">{book.autor_knjige}</Typography>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">{book.opis_knjige && book.opis_knjige.split(' ').splice(0, 20).join(' ')}...</Typography>
<Typography variant="body2" color="textSecondary" component="p> {book.rejting}</Typography>
</CardContent>
<div className={classes.details}>
<Typography variant="body2" color="textSecondary" component="h2 {book.zanr && book.zanr.map((zanr) => `#${zanr} `)}</Typography>
</div>
</ButtonBase>
<CardActions className={classes.cardActions}>
{(user && user.result.admin_stranice === true) && (
<Button size="small" color="secondary" onClick={() => dispatch(deleteBook(book._id))}>
<DeleteIcon fontSize="small" /> Delete
</Button>
)}
</CardActions>
</Card>
);
};
export default Book;
The object "book" i pass here is defined and have all the atributes needed and their values. I used console.log to see object in console and it's there, with everything it should have. But when i try to access any of atributes the JavaScript sees them as undefined for some reason. Some idea why it does that?
I've been trying to conditionally render the list items based on the user's selection but i can't seem to figure it out. I'd like to guide the users through steps in order to arrive at a final solution. I even tried rendering a different menu but it looks like the component does not re-render once the option selected change so the menu stays the same.
import React, { Fragment, useState, useEffect } from 'react';
import Typography from '#material-ui/core/Typography';
import Grid from '#material-ui/core/Grid';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
function TroubleshootingForm() {
const [anchorEl, setAnchorEl] = useState(null);
const [softorHardProb, setSoftorHardProb] = useState(null);
const [selectedIndex, setSelectedIndex] = useState(1);
const options = ['Select issue type', 'Software', 'Hardware'];
const softwareOptions = ['Smart Assistant', 'Sounds', '3rd Party Apps', 'OPPO Clone Phone'];
const hardwareOptions = ['Dislay', 'Battery', 'Charger', 'DOA'];
const handleClickListItem = event => {
setAnchorEl(event.currentTarget);
};
const handleMenuItemClick = (event, index) => {
setSelectedIndex(index);
setAnchorEl(null);
console.log(selectedIndex);
};
const handleClose = () => {
setAnchorEl(null);
};
// useEffect(() => {}, []);
return (
<Fragment>
<Typography variant="h6" gutterBottom>
Hardware or Software?
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<div>
<List component="nav" aria-label="Device settings">
<ListItem
button
aria-haspopup="true"
aria-controls="lock-menu"
aria-label="when device is locked"
onClick={handleClickListItem}
>
<ListItemText
primary="When device is locked"
secondary={
selectedIndex === 1
? options[selectedIndex]
: softwareOptions[
(
<ListItemText
primary="When device is locked"
secondary={
selectedIndex === 1
? options[selectedIndex]
: softwareOptions[selectedIndex]
}
/>
)
]
}
/>
</ListItem>
</List>
<Menu
id="lock-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
{options.map((option, index) => (
<MenuItem
key={option}
disabled={index === 0}
selected={index === selectedIndex}
onClick={event => handleMenuItemClick(event, index)}
>
{option}
</MenuItem>
))}
</Menu>
</div>
</Grid>
{/* <Grid item xs={12}>
{renderNextstep()}
</Grid> */}
</Grid>
</Fragment>
);
}
export default TroubleshootingForm;
The idea is for the user to chose options and the render the next step with other options and then so on until the final solution based on the previous selection. I added a screenshot from another app and the idea is that the current rendering of the component changes based on the selection. It starts by showing step 1 > select an option and component re-renders showing step 2 etc...
The below function is going to be run on a loop. I want to add styles to the icon which I want to pass as an argument to the function.
The icon is a going to be an unknown React Material-UI Icon component.
const renderStyledCard = (lightMode, heading, num, icon) => {
const classes = lightMode ? useLightCardStyles(): useDarkCardStyles();
return (
<Card className={classes.root}>
<CardContent>
<Typography variant="h4" component="h4" className={classes.textColor}>
{heading}
</Typography>
<div className={classes.content}>
<Typography variant="h4" component="h4" className={classes.textColor}>
{num}
</Typography>
{icon}
// Ex. <VpnKey className={[classes.icon, classes.textColor]} />
// Ex. <AccountCircle className={[classes.icon, classes.textColor]} />
{icon}
</div>
</CardContent>
</Card>
);
};
Loop execution is going to be like -
return [
{light: true,
heading: 'Accounts',
num: 100,
icon: <AccountCircle />
},
...theRest
].map(ele => renderStyledCard(...ele))
The loop code could be wrong I just wrote it here as an example to show how I wanted to execute it. Is there a better way? Any help would be awesome.
Some notice points:
add {} like ({ light, heading, num, icon }) to list the props
props lightMode not match list attribute light, need to change one of them
use Material-UI nesting selector & svg to customize the icon style from its parent div
Full code sample:
import React from "react";
import "./styles.css";
import GetApp from "#material-ui/icons/GetApp";
import AccountCircle from "#material-ui/icons/AccountCircle";
import { Card, CardContent, Typography, makeStyles } from "#material-ui/core";
const useLightCardStyles = makeStyles(theme => ({
root: {},
content: {
"& svg": {
color: "red"
}
}
}));
const useDarkCardStyles = makeStyles(theme => ({}));
const data = [
{ light: true, heading: "Accounts", num: 100, icon: <AccountCircle /> },
{ light: true, heading: "Accounts", num: 100, icon: <GetApp /> }
];
const StyledCard = ({ light, heading, num, icon }) => {
const lightCardClasses = useLightCardStyles();
const darkCardClasses = useDarkCardStyles();
const classes = light ? lightCardClasses : darkCardClasses;
return (
<Card className={classes.root}>
<CardContent>
<Typography variant="h4" component="h4" className={classes.textColor}>
{heading}
</Typography>
<div className={classes.content}>
<Typography variant="h4" component="h4" className={classes.textColor}>
{num}
</Typography>
{icon}
</div>
</CardContent>
</Card>
);
};
export default function App() {
return (
<div className="App">
{data.map(props => (
<StyledCard {...props} />
))}
</div>
);
}
I think this should work:
const renderStyledCard = (lightMode, heading, num, icon) => {
const classes = lightMode ? useLightCardStyles(): useDarkCardStyles();
icon.style.color = "red";
return(/*....*/)
}
Try console.log(icon.style)
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)
}