Data-Grid events firing on init and not after - reactjs

Background: Hello, I am using React with the latest MUI version of Material-UI. I am using Data-Grid in a separate file in my components folder. I call the component from my App and use states to handle adding rows. On init 50 rows are added.
Issue: When I add onRowEditStart={console.log("Start")} & onRowEditStop={console.log("stop")} to the DataGrid component, they are only fired on page load, but if I edit a column after, no events are fired?
Whole components/DataGrid.js added.
If anyone has info on this would be great, thanks!
import * as React from 'react';
import { DataGrid, GridToolbar } from '#mui/x-data-grid';
import Box from '#mui/material/Box';
import Stack from '#mui/material/Stack';
import Button from '#mui/material/Button';
export default function Table(props) {
const [rows, setRows] = React.useState(props.rows);
React.useEffect(() => {
setRows(props.rows);
}, [props.rows]);
return (
<div style={{ width: '100%' }}>
<Stack
sx={{ width: '100%', mb: 1 }}
direction="row"
alignItems="flex-start"
columnGap={1}
>
</Stack>
<Box sx={{ height: 400, bgcolor: 'background.paper' }}>
<DataGrid autoHeight
components={{
Toolbar: GridToolbar,
}}
pageSize={25}
rowsPerPageOptions={[25, 50, 100]}
onRowEditStart={console.log("Start")}
onRowEditStop={console.log("stop")}
experimentalFeatures={{ newEditingApi: true }}
rows={rows}
columns={props.columns}
loading={props.rows.length === 0}
columnGap={1}
rowHeight={75}
/>
</Box>
</div>
);
}

The reason for this is because both onRowEditStart and onRowEditStop accept functions.
If you replace your code with the following, it will work.
onRowEditStart={() => console.log("Start")}
onRowEditStop={() => console.log("stop")}
Notice the difference in your code.
onRowEditStart={console.log("Start")} // evaluated on page load
onRowEditStop={console.log("stop")} // evaluated on page load
By passing a function (onRowEditStart={() => console.log("Start")}), the console.log("Start") will only be run when a row edit has started.

Related

Unable to alternate colours in Material UI Datagrid v5 Reactjs

I am trying to achieve alternate colouring in my Material UI datagrid(1 row being blue other white) but am not able to do so. I am using Material UI v5 for Reactjs.
Table.js
import * as React from "react";
import { DataGrid,gridClasses } from "#mui/x-data-grid";
import "./style.css";
export default function DataTable(props) {
return (
<div style={{}}style={{ height: 585, width: "100%" }}>
<DataGrid
style={{ letterSpacing: "1px" }}
rows={props.rows}
columns={props.columns}
pageSize={5}
rowsPerPageOptions={[5]}
// getRowClassName={(params) => `super-app-theme--${params.row.status}`}
getRowClassName={(params) =>
params.indexRelativeToCurrentPage % 2 === 0 ? 'blue' : 'black'
}
// checkboxSelection
sx={{
fontFamily: 'Montserrat',
fontSize: '14px',
fontWeight: '550',
color: "black",
backgroundColor: "#FAF9F6",
}}
/>
</div>
);
}
I tried using the getRowClassName parameter with the indexRelativeToCurrentPage but with no effect. Any help regarding this is appreciated!
You can fix this problem by creating a new DataGrid by using styled components.
MUI X has a demo on it is documentation. Check the Striped rows

React - MUI styled div causes rerendering and fetching data multiple times on window resizing

I am displaying multiple charts in a Grid. Every chart fetches different data from my server.
When I resize the window the data is fetched again and the chart renders from scratch. I want to avoid the re-fetching.
I use highcharts as chart library, useQuery to fetch data (tried with useEffect hook aswell) and a Grid from material UI.
Update to my original question:
I have wrapped my app.js in a dashboard layout. This layout uses a MUI styled component. I figured when I use a normal div instead, the re-fetching stops. But also the Outlet is not displayed correctly as it's hidden behind the sidebar.
Here are my Components:
dashboard-layout.js
import { useState } from 'react';
import { DashboardNavbar } from './dashboard-navbar';
import { DashboardSidebar } from './dashboard-sidebar';
import { DashboardContent } from './dashboard-content';
import { DrawerContextProvider } from "../../contexts/drawer-context";
export const DashboardLayout = (props) => {
const [isSidebarOpen, setSidebarOpen] = useState(true);
return (
<>
<DrawerContextProvider>
<DashboardContent/>
<DashboardNavbar onSidebarOpen={() => setSidebarOpen(true)} />
<DashboardSidebar
onClose={() => setSidebarOpen(false)}
open={isSidebarOpen}
/>
</DrawerContextProvider>
</>
);
};
DashboardContent.js
import { Box, useMediaQuery } from '#mui/material';
import { useTheme, styled } from '#mui/material/styles';
import { Outlet } from 'react-router-dom';
import { useDrawerContext } from "../../contexts/drawer-context";
import DashboardFooter from './dashboard-footer';
export const DashboardContent = () => {
const { isOpened } = useDrawerContext();
const theme = useTheme();
const isLargeScreen = useMediaQuery(theme.breakpoints.up("md"));
const DashboardContentRoot = styled('div')(({ theme }) => ({
display: 'flex',
flex: '1 1 auto',
maxWidth: '100%',
paddingTop: 64,
paddingLeft: isLargeScreen && isOpened ? 280 : 0
}));
return (
<DashboardContentRoot >
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
width: '100%',
px: isLargeScreen ? 1.5 : 1,
py: isLargeScreen ? 1.5 : 1
}}
>
<Outlet/>
<DashboardFooter />
</Box>
</DashboardContentRoot>
);
};
The problem with re-rendering and therefore re-fetching persists even when I empty DashboardContentRoot like so:
const DashboardContentRoot = styled('div')(({ theme }) => ({
}));
but when I use div instead, no refetching happens:
<div>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
width: '100%',
px: isLargeScreen ? 1.5 : 1,
py: isLargeScreen ? 1.5 : 1
}}
>
<Outlet/>
<DashboardFooter />
</Box>
</div>
Components for my original question:
Chart.js
import React from "react";
import { useQuery } from "react-query";
import '../HighchartsStyle.css';
async function fetchData(){
const data = await (
await fetch("myserver/data")
).json()
console.log("fetching again")
return data
}
export default function Chart1(){
const {status, data, error, isLoading } = useQuery('data', fetchData);
return (
<div>
hohoho
</div>
);
}
Grid.js
import React from "react";
import { Chart1 } from "../components/charts/Chart1";
export default function ChartOverviewView() {
return (
<div >
<Chart1 />
</div>
);
}
fetching again is displayed every time I resize the window. I want to fetch the data once. Save it temporarily and use the already-fetched data every time I have to rerender the chart again.
What is the best practice to do so?
Thanks!
I am not sure if this suggestion works.
declare a variable with useRef.
then
if(useRefVariable.current !== data[1]) setSeriesData(data[1]);
try changing like this... If the previous state is equal with the new state then don't run setState or you could do smth like this
setSeriesData((prev)= > {if(!lodash.isEqual(prev, data[1])) return data[1]})
you should use lodash library to check if objects are equal. second way might be more professional looking
The re-rendering and therefore re-fetching of data happened because I wrapped my application in a dashboard-layout and for displaying the dashboard content depending on the state of the sidebar (opened or closed) I used a styled div component with MUI.
I don't know why this happened, but when I changed to using a Box instead, re-rendering stopped.
My dashboard content now looks like this:
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
maxWidth: '100%',
paddingTop: '64px',
paddingLeft: isLargeScreen && isOpened ? '280px' : 0
}}
>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
width: '100%',
px: isLargeScreen ? 1.5 : 1,
py: isLargeScreen ? 1.5 : 1
}}
>
<Outlet/>
<DashboardFooter />
</Box>
</Box>

Can I Change Box background color on click in material ui with typescript?

I want to change the background color of my Box whenever it is clicked.
OOTB i couldn't find something which could help my use case.
SO, I tried using events onClick but couldn't find the right event which could bring info on selected event and allow me to change the styling value.
Use Case -
i am creating multiple box dynamically and at once only one Box could be highlighted
{allSports !== null &&
allSports?.map((sports) => (
<Grid
item
xs={4}
sx={{ mx: "auto", my: 1, minWidth: "80%" }}
onClick={backgroundChange}
>
<Item
// onClick={() => sportChoose(sports)}
>
<Box sx={{ display: "flex", justifyContent: "space-evenly" }}>
<Box>
<img
src={
require(`../../../../../resources/images/sportsIcons/${sports.icon}`)
.default
}
/>
</Box>
<Box sx={{ m: "auto" }}>
<Typography variant="h6">{sports.name}</Typography>
</Box>
</Box>
</Item>
</Grid>
))}
import { FC, ReactElement, useState } from 'react'
import { Box } from '#mui/material'
export const MuiCard: FC = (): ReactElement => {
const [clicked, setClicked] = useState(false)
const toggleClicked = () => setClicked((prev) => !prev)
return (
<Box
component="div"
onClick={toggleClicked}
sx={{ height: 20, backgroundColor: clicked ? 'red' : 'white' }}
/>
)
}

Material-UI: How to center pagination button?

I tried to get Pagination from Material-UI
but I want to center the buttons of the arrow and number of page.
I tried to center by creating a <div style={{textAlign: "center"}}> but it doesn't work because it came all in one box.
there is any way to get inside the this component and make the numbers and button to get in the center?
If you're using TablePagination, you need to remove the spacer div which push the pagination content to the right and set the container justify-content to center:
import TablePagination, {
tablePaginationClasses
} from "#mui/material/TablePagination";
<TablePagination
sx={{
[`& .${tablePaginationClasses.spacer}`]: {
display: "none"
},
[`& .${tablePaginationClasses.toolbar}`]: {
justifyContent: "center"
}
}}
{...}
/>
If you're using the Pagination from DataGrid, just set the justify-content to center because the container is already flex:
import { makeStyles } from "#mui/styles";
import { paginationClasses } from "#mui/material/Pagination";
const useStyles = makeStyles({
root: {
[`& .${gridClasses.footerContainer}`]: {
justifyContent: "center"
}
}
});
<DataGrid pagination {...data} className={classes.root} />
Their Pagination component is using display: flex. Adding the following style rule should achieve what you're trying to do
.MuiPagination-ul { justify-content: center; }
using below code
<Box display="flex" justifyContent="center">
<Pagination ... />
</Box>
To center pagination, i suggest you wrap it inside a Grid System, then put it in the middle of two grid items with the flexGrow property equal to 1.
<Grid container>
<Grid item sx={{ flexGrow: 1 }}></Grid>
<Grid item>
<Pagination />
</Grid>
<Grid item sx={{ flexGrow: 1 }}></Grid>
</Grid>

How do I set a width for the TextAreaAutoSize component in Material-UI?

I can't find any info anywhere on how to change the default width of a TextAreaAutosize component in material-ui.
It seems the only choice is to have this little box. Does anyone know of a better text area auto size component I can use, or how to change the width of the TextAreaAutoSize component?
The API doesn't show any properties that have anything to do with 'className'. I tried to use it anyway and it was ignored. I also tried wrapping the component in a Box, and styling that, but it was ignored by the TextArea.
Any help would be greatly appreciated!
Resizing by the user is turned off (via resize: "none") for TextField here in InputBase: https://github.com/mui-org/material-ui/blob/v4.10.2/packages/material-ui/src/InputBase/InputBase.js#L140.
Below is an example of how to turn it back on:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles(theme => ({
root: {
"& .MuiTextField-root": {
margin: theme.spacing(1)
}
},
textarea: {
resize: "both"
}
}));
export default function MultilineTextFields() {
const classes = useStyles();
return (
<form className={classes.root} noValidate autoComplete="off">
<div>
<TextField
id="outlined-textarea"
label="Multiline Placeholder"
placeholder="Placeholder"
multiline
variant="outlined"
inputProps={{ className: classes.textarea }}
/>
</div>
</form>
);
}
CSS documentation for resize: https://developer.mozilla.org/en-US/docs/Web/CSS/resize
Multiline TextField demos: https://material-ui.com/components/text-fields/#multiline
You can change the style prop of the TextareaAutosize check here
<TextareaAutosize
rowsMin={3}
placeholder=''
defaultValue=''
style={{ width: "100%" }}
/>
I was able to get it to work thanks to Ryan Cogswell. Stupid me, though I wrapped the textarea in a box and applied className to the box (which didn't work), I should have applied it to the textareaautosize directly.
There's a bug in VSCODE Intellisense where it shows 'classes' as a property but not 'className' so I assumed it didn't exist.
Here's the code:
const FormStyles = makeStyles((theme) => ({
root: {
width: '100%',
},
button: {
marginTop: '20px',
marginRight: theme.spacing(1),
},
buttons: {
display: 'flex',
justifyContent: 'flex-end'
},
textarea: {
width: '100%',
},
}));
<TextareaAutosize
rowsMin={3}
aria-label={info.label}
name={info.name}
placeholder=''
defaultValue=''
className={classes.textarea}
/>
I could not get the drag icon to show up in textfield, so didn't use it. But I would appreciate an example of textfield using multiline and resizing.
Thanks Ryan!
Here's the trick I used. I wrapped it in a flex container and used align-items to stretch the width to cover the size of that container.
<Stack
direction="column"
justifyContent="center"
alignItems="stretch"
spacing={2}
>
<TextareaAutosize
label='Title'
value={pub.title || ''}
onChange={(e) => pub.title = e.target.value}
variant='outlined'
sx={{m: 1}}
size='small'
/>
</Stack>

Resources