I want to prevent re-render of child component - javascript

I am using three child components in my parent that is m show under according to when I click in Accordion this child component re-render again and again when I click because of this Accordion get slow to open take time because some time data will come in a large amount I have tow child component like this and my data is not getting change I have already stored in some state before coming in this Accordion section
import React from 'react'
import {
Box,
makeStyles,
Typography,
Paper,
Grid,
Card,
CardContent,
} from "#material-ui/core";
function childComponent({data, title, classes}) {
console.log("child rerender dataChnage")
const Memodata = React.useMemo(() => {
return data
},[data]);
return (
<>
<Box mt={2}>
<Typography variant="subtitle2" noWrap={true}>
<Box fontWeight="fontWeightBold">{title}</Box>
</Typography>
</Box>
{Memodata?.map((row, rowIndex) => {
return (
<>
{Memodata?.length !== 0 ? (
<Card className={classes.cardSpace} variant="outlined">
<CardContent>
<Grid xs={12} item container spacing={2}>
<Grid item xs={12} sm={3}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
name :
</Box>
{row.SRN}
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
ID :
</Box>
{row.CHARGE_ID ? row.CHARGE_ID : "N/A"}
</Typography>
</Grid>
<Grid item xs={12} sm={6}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
Holder :
</Box>
{row.CHARGE_HOLDER ? row.CHARGE_HOLDER : "N/A"}
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
Date Create :
</Box>
{row.DATE_CREATE ? row.DATE_CREATE : "N/A"}
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
Date Modified :
</Box>
{row.DATE_MODIFIED ? row.DATE_MODIFIED : "N/A"}
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
Date Satisfied :
</Box>
{row.DATE_SATISFIED ? row.DATE_SATISFIED : "N/A"}
</Typography>
</Grid>
<Grid item xs={12} sm={3}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
Amount :
</Box>
{row.AMOUNT ? row.AMOUNT : "N/A"}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="subtitle2">
<Box fontWeight="fontWeightBold" component="span" mr={1}>
Address :
</Box>
{row.ADDRESS ? row.ADDRESS : "N/A"}
</Typography>
</Grid>
</Grid>
</CardContent>
</Card>
) : (
<Typography variant="subtitle2">No Data Available.</Typography>
)}
</>
);
})}
</>
)
}
export default React.memo(childComponent);
Passing data in the child component
{MemoUserHistorySummary?.masterData?.map((row, i) => {
return (
<Accordion
expanded={expanded === i}
onChange={handleChange(i)}
elevation={0}
className={classes.bgColor}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
aria-controls="panel1bh-content"
id="panel1bh-header"
>
<Grid container direction="row">
<Grid item xs={12} md={6}>
<Grid item xs={12}>
<Box display="flex">
<Grid item xs={8} sm={4} md={3}>
<Box overflow="hidden" width="100%">
<Typography component={"div"} variant="subtitle">
<Box
fontWeight="fontWeightBold"
overflow="hidden"
whiteSpace="nowrap"
textOverflow="ellipsis"
>
Name :
</Box>
</Typography>
</Box>
</Grid>
<Grid item xs={9} sm={8} md={9}>
<Typography component={"div"} variant="subtitle">
{row.NAME}
</Typography>
</Grid>
</Box>
<Grid item xs={12}>
<Typography variant="subtitle">
<Box display="flex" flexWrap="wrap">
<Box mr={1} fontWeight="fontWeightBold">
ID :
</Box>
{row.ID}
</Box>
</Typography>
</Grid>
</Grid>
</Grid>
<Grid container item xs={12} md={6}>
<Grid item xs={2}>
<Box overflow="hidden" width="100%">
<Typography component={"div"} variant="subtitle">
<Box
fontWeight="fontWeightBold"
overflow="hidden"
whiteSpace="nowrap"
textOverflow="ellipsis"
>
Address :
</Box>
</Typography>
</Box>
</Grid>
<Grid item xs={10}>
<Box display="flex">
<Typography
component={"div"}
variant="subtitle"
title={row.REGISTERED_OFFICE_ADDRESS}
>
{row.REGISTERED_OFFICE_ADDRESS.slice(0, 110)}
</Typography>
</Box>
</Grid>
</Grid>
</Grid>
</AccordionSummary>
<AccordionDetails>
<Grid item xs={12}>
<DetailsCards
companyName="Name"
row={row}
mainDetailData={corporateCells}
show={show}
setShow={setShow}
/>
<DownloadsChargesCard
data={MemoUserHistorySummary?.charges}
title={"Charges Registered"}
cells={chargesCells}
classes={classes}
/>
<DownloadDiractorCard
data={MemoUserHistorySummary?.directors_history}
title={"Directors List"}
cells={signatoriesCells}
classes={classes}
/>
</Grid>
</AccordionDetails>
</Accordion>
);
})}

You basically need to implement shouldComponentUpdate() on the children components and have it return false when the state or prop that causes the parent accordion to expand is the only value in nextProps or nextState (depending how you are controlling your accordion, which I couldn't tell from your code sample).

Related

Formik Warning: Maximum update depth exceeded

I am working on EDIT formik form, this form is in form of MODAL. when setState is passed as setState(true) than form will appear. But the problem is that without clicking onClick setState is being triggerd (according to error). In form values are already passed as it is EDIT form. I changed onClick={editStory} to onClick={()=> editStory()} still error not gone
Error: "Warning: Maximum update depth exceeded. This can happen when a
component calls setState inside useEffect, but useEffect either
doesn't have a dependency array, or one of the dependencies changes on
every render.
at EditQs (webpack-internal:///./src/new-components/Projects/EditQs.js:106:23)"
MyQs2.js
function MyQs2({row, isItemSelected, labelId, index}) {
const theme = useTheme();
const editStory = () => {
console.log('editstory is triggering')
setOpenStoryDrawer(true);
};
const [openStoryDrawer, setOpenStoryDrawer] = React.useState(false);
const handleStoryDrawerOpen = () => {
setOpenStoryDrawer(false);
};
const [allUsers, setAllUsers] = React.useState([])
const [allUsersObj, setAllUsersObj] = React.useState([])
const [allProjects, setAllProjects] = React.useState([])
//Error occur in this useEffect but i need updated data to show from firestore
React.
useEffect(() => {
readAllUsers()
readAllProjects()
}, [])
const readAllUsers = async()=> {
console.log('readAllUsesrs is calling')
try{
firebase.firestore().collection("users").where("role", "==", 'user')
.onSnapshot(function (val) {
let user = []
val.forEach(function(doc) {
user.push(doc.data().name);
setAllUsers(user)
})})
}
const readAllProjects = async() => {
console.log('readAllUsesrs is calling')
const snapshot = await firebase.firestore().collection('projects').get()
setAllProjects( snapshot.docs.map(doc => doc.data().name) );
}
return (
<>
<TableRow hover role="checkbox" aria-checked={isItemSelected} tabIndex={-1} key={index} selected={isItemSelected}>
<TableCell padding="checkbox" sx={{ pl: 3 }} onClick={(event) => handleClick(event, row.question)}>
<Checkbox
color="primary"
checked={isItemSelected}
inputProps={{
'aria-labelledby': labelId
}}
/>
</TableCell>
<TableCell
component="th"
id={labelId}
scope="row"
onClick={(event) => handleClick(event, row.projects)}
sx={{ cursor: 'pointer' }}
>
<Typography variant="subtitle1" sx={{ color: theme.palette.mode === 'dark' ? 'grey.600' : 'grey.900' }}>
{' '}
{row.question}{' '}
</Typography>
<Typography variant="caption"> {row.projects} </Typography>
</TableCell>
<TableCell>{row.projects}</TableCell>
<TableCell align="right">{row.assignTo}</TableCell>
<TableCell align="center">{row.priority}</TableCell>
<TableCell align="center">
{row.state === "published" && <Chip label="published" size="small" chipcolor="success" />}
{row.state === "unpublished" && <Chip label="unpublished" size="small" chipcolor="orange" />}
{row.state === 'Active' && <Chip label="Confirm" size="small" chipcolor="primary" />}
</TableCell>
<TableCell align="center" sx={{ pr: 3 }}>
<IconButton color="primary" size="large">
<VisibilityTwoToneIcon sx={{ fontSize: '1.3rem' }} />
</IconButton>
//below onClick is triggering
<IconButton color="secondary" size="large" onClick={()=> editStory()}
<EditTwoToneIcon sx={{ fontSize: '1.3rem' }} />
</IconButton>
</TableCell>
</TableRow>
// This calls a EditPage
<EditQs existingQs={row} open={openStoryDrawer} handleDrawerOpen={handleStoryDrawerOpen} allProjects={allProjects} allUsers={allUsers} />
</>
);
}
export default MyQs2
According to error appears in this Form page
EditQs.js
const EditQs = ({ open, handleDrawerOpen, existingQs, allProjects, allUsers }) => {
const dispatch = useDispatch();
const sendDataToFirestore = (item) => {
try{
firebase.firestore()
.collection('projects')
.doc(item.projects)
.update({
question : firebase.firestore.FieldValue.arrayUnion(item)
}).then(
dispatch(
openSnackbar({
open: true,
message: 'New Question added',
variant: 'alert',
alert: {
color: 'success'
},
close: false
})
)
)
}catch(err){
console.log('an error occured', err)
}
}
const formik = useFormik({
enableReinitialize: true, //if i remove this, error gone but this is responsible
for adding values in formik during render
validateOnChange:false,
validateOnBlur:false,
initialValues: {
id: existingQs.id ? existingQs.id : '',
question: existingQs.question? existingQs.question : '',
projects: existingQs.projects? existingQs.projects : '',
assignTo: existingQs.assignTo ? existingQs.assignTo : '',
priority: existingQs.priority ? existingQs.priority : '',
dueDate: existingQs.dueDate ? new Date(existingQs.dueDate) : new Date(),
state: existingQs.state ? existingQs.state : '',
image: existingQs.image
},
validationSchema,
onSubmit: (values,{resetForm}) => {
const item = {
id: values.id,
question: values.question,
projects: values.projects,
assignTo: values.assignTo,
priority: values.priority,
dueDate: values.dueDate ? new Date(values.dueDate) : new Date(),
state: values.state,
image: values.image
};
sendDataToFirestore(item);
() => handleDrawerOpen();
resetForm()
readAllProjects()
}
});
return (
<Drawer
sx={{
ml: open ? 3 : 0,
flexShrink: 0,
zIndex: 1200,
overflowX: 'hidden',
width: { xs: 320, md: 450 },
'& .MuiDrawer-paper': {
height: '100vh',
width: { xs: 320, md: 450 },
position: 'fixed',
border: 'none',
borderRadius: '0px'
}
}}
variant="temporary"
anchor="right"
open={open}
ModalProps={{ keepMounted: true }}
onClose={() => handleDrawerOpen}
>
{open && (
<Box sx={{ p: 3 }}>
<form onSubmit={formik.handleSubmit}>
<LocalizationProvider dateAdapter={AdapterDateFns}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="h4">Edit Question</Typography>
</Grid>
<Grid item xs={12}>
<Grid container alignItems="center" spacing={2}>
<Grid item xs={12} sm={4}>
<Typography variant="subtitle1">Question:</Typography>
</Grid>
<Grid item xs={12} sm={8}>
<TextField
fullWidth
id="question"
name="question"
multiline
rows={3}
value={formik.values.question}
onChange={formik.handleChange}
error={formik.touched.question && Boolean(formik.errors.question)}
helperText={formik.touched.question && formik.errors.question}
/>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container alignItems="center" spacing={2}>
<Grid item xs={12} sm={4}>
<Typography variant="subtitle1">Assign to:</Typography>
</Grid>
<Grid item xs={12} sm={8}>
<FormControl fullWidth sx={{ m: 1 }}>
<InputLabel>Choose a user</InputLabel>
<Select
id="assignTo"
name="assignTo"
displayEmpty
value={formik.values.assignTo}
onChange={formik.handleChange}
label='Assign to'
inputProps={{ 'aria-label': 'assignTo' }}
>
{allUsers.map((val, index) => (
<MenuItem key={index} value={val}>
{val}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container alignItems="center" spacing={2}>
<Grid item xs={12} sm={4}>
<Typography variant="subtitle1">project:</Typography>
</Grid>
<Grid item xs={12} sm={8}>
<FormControl fullWidth sx={{ m: 1 }}>
<InputLabel>Choose a Project</InputLabel>
<Select
id="projects"
name="projects"
displayEmpty
value={formik.values.projects}
onChange={formik.handleChange}
label='projects'
inputProps={{ 'aria-label': 'projects' }}
>
{allProjects.map((val, index) => (
<MenuItem key={index} value={val}>
{val}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container alignItems="center" spacing={2}>
<Grid item xs={12} sm={4}>
<Typography variant="subtitle1">Prioritize:</Typography>
</Grid>
<Grid item xs={12} sm={8}>
<FormControl>
<RadioGroup
row
aria-label="color"
value={formik.values.priority}
onChange={formik.handleChange}
name="priority"
id="priority"
>
<FormControlLabel value="low" control={<Radio color="primary" sx={{ color: 'primary.main' }} />} label="Low" />
<FormControlLabel
value="medium"
control={<Radio color="warning" sx={{ color: 'warning.main' }} />}
label="Medium"
/>
<FormControlLabel value="high" control={<Radio color="error" sx={{ color: 'error.main' }} />} label="High" />
</RadioGroup>
</FormControl>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<Grid container alignItems="center" spacing={2}>
<Grid item xs={12} sm={4}>
<Typography variant="subtitle1">State:</Typography>
</Grid>
<Grid item xs={12} sm={8}>
<FormControl fullWidth sx={{ m: 1 }}>
<InputLabel >State of question</InputLabel>
<Select
id="state"
name="state"
displayEmpty
value={formik.values.state}
onChange={formik.handleChange}
// label='choose question state'
inputProps={{ 'aria-label': 'choose question state' }}
>
{states.map((val, index) => (
<MenuItem key={index} value={val.title}>
{val.title}
</MenuItem>
))}
</Select>
</FormControl>
</Grid>
</Grid>
</Grid>
<Grid item xs={12}>
<AnimateButton>
<Button fullWidth variant="contained" type="submit">
Save
</Button>
</AnimateButton>
</Grid>
</Grid>
</LocalizationProvider>
</form>
</Box>
)}
</Drawer>
);
};
export default EditQs;
First issue is setAllUsers(readAllUsers()). You are calling setAllUsers passing a function readAllUsers as argument but inside this function you are calling setAllUsers again
.onSnapshot(function (val) {
let user = []
val.forEach(function(doc) {
user.push(doc.data().name);
// setAllUsers again
setAllUsers(user)
})})
Every time you change the state, your component is getting rerendered.
It would be better to write different useEffect for each state setup. Each useEffect will have different dependentcies. Setting correct depencencies needs analysing the code. Otherwise you might not get correct state or your component might keep rerendering

Remove Padding From Material UI Grid System

I hope your day is going well. I am a new user of material UI and I am working on building my first profile page (image below).
As I am getting closer to building this page, I am struggling to create a grid system that allows the about section to be directly under the three panels (see image below).
How do I remove the padding between the about section and three pannels (code below)?
return (
<>
<Helmet>
<title>Dashboard: Project Details | Material Kit Pro</title>
</Helmet>
<Box
sx={{
backgroundColor: 'background.default',
minHeight: '100%',
py: 8
}}
>
<Container >
<AppBar></AppBar>
<Grid container spacing={1}>
<Grid item xs={12} md={3}>
<Box
style={{ height: '100%', width: '100%'}}
>
<WritersSidePanel />
</Box>
</Grid>
<Grid item xs={12} md={9}>
<WritersPageTopPanel />
</Grid>
<Box style={{ marginDown: '90%'}}>
<Grid item xs={12} container
direction="column"
alignItems="flex-end"
justify="flex-end">
<Box
style={{ width: '75%', height: '100%'}}
>
<AboutSection description={description} />
</Box>
</Grid>
<Grid item xs={12} container
direction="column"
alignItems="flex-end"
justify="flex-end">
<Box
style={{ width: '75%'}}
>
<SampleStory description={description} />
</Box>
</Grid>
</Box>
</Grid>
</Container>
</Box>
</>
);
};

Reactjs how to make the inputs in them work independently of each other, when you add a form button?

How can I make the state in the added forms work independently of changes in other similar forms?
Forms are added through locationAdd
const LocationBody = ({filteredServersData, locationAdd,
deleteLocationCell, handleChangeFilter,
filters, locationsData, envsData }) => {
const classes = useStyles();
const locationsSelect = locationsData.map((item) => {
return <MenuItem key={item.locationID} value={item.locationID}>{item.name}</MenuItem>;
})
const envsSelect = envsData.map((item, index) => {
return <MenuItem key={index} value={item.envID}>{item.name}</MenuItem>;
})
const serversSelect = filteredServersData.map(item => <Typography variant="h6" component="h1">
{item.name}
</Typography>)
return (
<div>
{locationAdd.map(i => <Container className={classes.root} key={i.id}>
<Grid container spacing={3} className="arr">
<Grid item xs={12}>
<Box display="flex" justifyContent="space-between">
<Typography variant="h5" component="h1">
Тестовая локация {i.id}
</Typography>
<IconButton
aria-label="delete" color="secondary"
className={classes.margin}
onClick={() => deleteLocationCell(i)}>
<DeleteIcon fontSize="medium" />
</IconButton>
</Box>
</Grid>
<Grid item xs={12} className={classes.filtersContainer}>
<Box display="flex" justifyContent="space-between">
<Box display="flex" className={classes.fieldsContainer}>
<Typography variant="h6" component="h1">
Локация
</Typography>
<FormControl variant="outlined">
<Select
value={filters.locationID}
onChange={handleChangeFilter}
label="LocationID"
labelId="locationID"
name="locationID"
>
{locationsSelect}
</Select>
</FormControl>
<FormControl variant="outlined">
<Select
value={filters.envID}
onChange={handleChangeFilter}
label="EnvID"
labelId="envID"
name="envID" >
{envsSelect}
</Select>
</FormControl>
{serversSelect}
</Box>
</Box>
</Grid>
</Grid>
</Container>)}
</div>
)
}
You can create a new component for added forms and each component will handle its own state only, without sharing it with other siblings.
Or, if you don't want to create a new component, and want to keep the current code as it is, you may differentiate each form's state by prefixing it with the form's unique ID.

How to imitate PaddingTop with Grid Material UI and fill empty rows from the top?

Suppose we have the Grid
const App = () => {
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
paper: {
padding: theme.spacing(2),
textAlign: "center",
color: theme.palette.text.secondary
}
}));
const classes = useStyles();
return (
<>
<Grid container>
<Grid item xs={8}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Paper className={classes.paper}>xs=12</Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>xs=12 sm=6</Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>xs=12 sm=6</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
</Grid>
</Grid>
<Grid item xs={4}>
<Grid item xs={12}>
</Grid>
</Grid>
</Grid>
</>
);
};
export default App;
How can we imitate PaddingTop and add empty rows from the top using Grid ?
You can acquire the space using spacing={10} in the top Grid container to adjust.
Also, you can add a new Grid with xs={12} if you want something to show.
import React from "react";
import "./styles.css";
import { Grid, makeStyles, Paper } from "#material-ui/core";
export default (App = () => {
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
paper: {
padding: theme.spacing(2),
textAlign: "center",
color: theme.palette.text.secondary
}
}));
const classes = useStyles();
return (
<>
<Grid container spacing={2}>
<Grid item xs={12}>
<Paper className={classes.paper}>xs=12</Paper>
</Grid>
<Grid item xs={8}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Paper className={classes.paper}>xs=12</Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>xs=12 sm=6</Paper>
</Grid>
<Grid item xs={12} sm={6}>
<Paper className={classes.paper}>xs=12 sm=6</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
<Grid item xs={6} sm={3}>
<Paper className={classes.paper}>xs=6 sm=3</Paper>
</Grid>
</Grid>
</Grid>
<Grid item xs={4}>
<Grid item xs={12} />
</Grid>
</Grid>
</>
);
});

Moving Grid layout within React

Hello i need to move my grids to display the following layout
However right now my layout looks like this
I am still trying to understand how grid work, below is my attempt at formatting the grid, however it doesn't want to align itself in the manor of which i wish
<Grid item xs={8}>
<Grid className = {classes.root} container direction ="column"
alignItems="flex-start">
{/* <Typography variant="title" style={{ }}>example</Typography> */}
<Paper className = {classes.mainDetailsPaper}>
<Typography variant="title">Main Details</Typography><Divider />
<Typography variant="subheading">Organisation: </Typography>
<Typography variant="subheading">Category: </Typography>
<Typography variant="subheading">Sub Category: </Typography>
</Paper>
</Grid>
<Grid className = {classes.root} container direction ="row"
alignItems="flex-end">
<Paper className = {classes.subDetailsPaper}>
<Typography variant="title">Contract Dates</Typography><Divider />
<Typography variant="subheading">Start Date: </Typography>
</Paper>
<Paper className = {classes.subDetailsPaper}>
<Typography variant="title">Valuation</Typography><Divider />
<Typography variant="subheading">Estimated Contract Value: </Typography>
</Paper>
<Paper className = {classes.subDetailsPaper}>
<Typography variant="title">Supplier Info</Typography><Divider />
</Paper>
</Grid>
</Grid>

Categories

Resources