optimistic-gold
optimistic-gold9mo ago

setFilter with useDataGrid on mount

In the example for filtering in useDataGrid docs, handleFilter is called onChange. But how do I setFilter on mount? Example from docs:

import { useDataGrid, List } from "@refinedev/mui";
import { FormControlLabel, Checkbox } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
type: "number",
},
{ field: "title", headerName: "Title" },
{ field: "status", headerName: "Status" },
];

export const PostsList: React.FC = () => {
const { dataGridProps, setFilters } = useDataGrid();

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
setFilters([
{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
},
]);
};

return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={<Checkbox onChange={handleFilter} />}
/>
<DataGrid {...dataGridProps} columns={columns} autoHeight />
</List>
);
};

import { useDataGrid, List } from "@refinedev/mui";
import { FormControlLabel, Checkbox } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
type: "number",
},
{ field: "title", headerName: "Title" },
{ field: "status", headerName: "Status" },
];

export const PostsList: React.FC = () => {
const { dataGridProps, setFilters } = useDataGrid();

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
setFilters([
{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
},
]);
};

return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={<Checkbox onChange={handleFilter} />}
/>
<DataGrid {...dataGridProps} columns={columns} autoHeight />
</List>
);
};
10 Replies
kapa.ai
kapa.ai9mo ago
Hi @soto76. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To set a filter on mount, you can use the useEffect hook from React. This hook allows you to perform side effects, such as setting a filter, in function components. You can call setFilters inside useEffect with an empty dependency array [], which means the effect will run once after the initial render. Here's how you can modify your PostsList component to set a filter on mount:
import { useDataGrid, List } from "@refinedev/mui";
import { FormControlLabel, Checkbox } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { useEffect } from "react";

const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
type: "number",
},
{ field: "title", headerName: "Title" },
{ field: "status", headerName: "Status" },
];

export const PostsList: React.FC = () => {
const { dataGridProps, setFilters } = useDataGrid();

useEffect(() => {
setFilters([
{
field: "status",
value: "draft",
operator: "eq",
},
]);
}, [setFilters]);

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
setFilters([
{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
},
]);
};

return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={<Checkbox onChange={handleFilter} />}
/>
<DataGrid {...dataGridProps} columns={columns} autoHeight />
</List>
);
};
import { useDataGrid, List } from "@refinedev/mui";
import { FormControlLabel, Checkbox } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { useEffect } from "react";

const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
type: "number",
},
{ field: "title", headerName: "Title" },
{ field: "status", headerName: "Status" },
];

export const PostsList: React.FC = () => {
const { dataGridProps, setFilters } = useDataGrid();

useEffect(() => {
setFilters([
{
field: "status",
value: "draft",
operator: "eq",
},
]);
}, [setFilters]);

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
setFilters([
{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
},
]);
};

return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={<Checkbox onChange={handleFilter} />}
/>
<DataGrid {...dataGridProps} columns={columns} autoHeight />
</List>
);
};
In this example, the useEffect hook sets the filter to show only draft posts when the component mounts. The handleFilter function will update this filter when the user interacts with the checkbox. Please note that this will trigger a new fetch as every change in filters will do so as mentioned in the useTable documentation (https://refine.dev/docs/api-reference/core/hooks/useTable/). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@934748406096736296> kapa.ai is still learning and improving, please let us know how it did by reacting below
optimistic-gold
optimistic-gold9mo ago
@kapa.ai this causes infinite re-renders
kapa.ai
kapa.ai9mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- I apologize for the confusion. The setFilters function updates the state and triggers a re-render. If it's called inside useEffect without any dependencies, it will indeed cause an infinite loop of re-renders. To avoid this, you can use a state variable to track if it's the first render. Here's how you can modify your PostsList component to set a filter on mount without causing infinite re-renders:
import { useDataGrid, List } from "@refinedev/mui";
import { FormControlLabel, Checkbox } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { useEffect, useState } from "react";

const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
type: "number",
},
{ field: "title", headerName: "Title" },
{ field: "status", headerName: "Status" },
];

export const PostsList: React.FC = () => {
const { dataGridProps, setFilters } = useDataGrid();
const [initialRender, setInitialRender] = useState(true);

useEffect(() => {
if (initialRender) {
setFilters([
{
field: "status",
value: "draft",
operator: "eq",
},
]);
setInitialRender(false);
}
}, [setFilters, initialRender]);

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
setFilters([
{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
},
]);
};
return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={<Checkbox onChange={handleFilter} />}
/>
<DataGrid {...dataGridProps} columns={columns} autoHeight />
</List>
);
};
import { useDataGrid, List } from "@refinedev/mui";
import { FormControlLabel, Checkbox } from "@mui/material";
import { DataGrid, GridColDef } from "@mui/x-data-grid";
import { useEffect, useState } from "react";

const columns: GridColDef[] = [
{
field: "id",
headerName: "ID",
type: "number",
},
{ field: "title", headerName: "Title" },
{ field: "status", headerName: "Status" },
];

export const PostsList: React.FC = () => {
const { dataGridProps, setFilters } = useDataGrid();
const [initialRender, setInitialRender] = useState(true);

useEffect(() => {
if (initialRender) {
setFilters([
{
field: "status",
value: "draft",
operator: "eq",
},
]);
setInitialRender(false);
}
}, [setFilters, initialRender]);

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {
setFilters([
{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
},
]);
};
return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={<Checkbox onChange={handleFilter} />}
/>
<DataGrid {...dataGridProps} columns={columns} autoHeight />
</List>
);
};
In this example, a state initialRender is used to track if it's the first render. When the component mounts, if it's the initial render, we set the filter and then set initialRender to false. This will prevent the useEffect hook from running on subsequent re-renders. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@934748406096736296> kapa.ai is still learning and improving, please let us know how it did by reacting below
optimistic-gold
optimistic-gold9mo ago
@kapa.ai seems like it's still an infinite loop, I am getting thiese error messages now: [Violation] 'click' handler took 224ms [Violation] 'click' handler took 172ms [Violation] 'message' handler took 189ms [Violation] 'setTimeout' handler took 99ms
kapa.ai
kapa.ai9mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- I apologize for the confusion earlier. The issue you're experiencing might be due to the asynchronous nature of the setFilters function. When you call setFilters and then immediately update the initialRender state, it might not have finished updating the filters yet, causing the infinite loop. To solve this, you can use the useRef hook to track the initial render instead of useState. The useRef hook creates a mutable ref object whose .current property is initialized with the passed argument (true). The returned object will persist for the full lifetime of the component. Here's how you can modify your PostsList component:
import {{ useDataGrid, List }} from "@refinedev/mui";
import {{ FormControlLabel, Checkbox }} from "@mui/material";
import {{ DataGrid, GridColDef }} from "@mui/x-data-grid";
import {{ useEffect, useRef }} from "react";

const columns: GridColDef[] = [
{{
field: "id",
headerName: "ID",
type: "number",
}},
{{ field: "title", headerName: "Title" }},
{{ field: "status", headerName: "Status" }},
];

export const PostsList: React.FC = () => {{
const {{ dataGridProps, setFilters }} = useDataGrid();
const initialRender = useRef(true);

useEffect(() => {{
if (initialRender.current) {{
setFilters([
{{
field: "status",
value: "draft",
operator: "eq",
}},
]);
initialRender.current = false;
}}
}}, [setFilters]);

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {{
setFilters([
{{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
}},
]);
}};
return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={{<Checkbox onChange={{handleFilter}} />}}
/>
<DataGrid {{...dataGridProps}} columns={{columns}} autoHeight />
</List>
);
}};
import {{ useDataGrid, List }} from "@refinedev/mui";
import {{ FormControlLabel, Checkbox }} from "@mui/material";
import {{ DataGrid, GridColDef }} from "@mui/x-data-grid";
import {{ useEffect, useRef }} from "react";

const columns: GridColDef[] = [
{{
field: "id",
headerName: "ID",
type: "number",
}},
{{ field: "title", headerName: "Title" }},
{{ field: "status", headerName: "Status" }},
];

export const PostsList: React.FC = () => {{
const {{ dataGridProps, setFilters }} = useDataGrid();
const initialRender = useRef(true);

useEffect(() => {{
if (initialRender.current) {{
setFilters([
{{
field: "status",
value: "draft",
operator: "eq",
}},
]);
initialRender.current = false;
}}
}}, [setFilters]);

const handleFilter = (
e: React.ChangeEvent<HTMLInputElement>,
checked: boolean,
) => {{
setFilters([
{{
field: "status",
value: checked ? "draft" : undefined,
operator: "eq",
}},
]);
}};
return (
<List>
<FormControlLabel
label="Filter by Draft Status"
control={{<Checkbox onChange={{handleFilter}} />}}
/>
<DataGrid {{...dataGridProps}} columns={{columns}} autoHeight />
</List>
);
}};
In this example, initialRender is a ref object. When the component mounts, if initialRender.current is true, we set the filter and then set initialRender.current to false. This will prevent the useEffect hook from running on subsequent re-renders. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@934748406096736296> kapa.ai is still learning and improving, please let us know how it did by reacting below
fair-rose
fair-rose9mo ago
Hello @soto76 you can use initialFilters prop for that. https://refine.dev/docs/api-reference/mui/hooks/useDataGrid/#filtersinitial
useDataGrid | refine
By using useDataGrid, you can get properties that are compatible with MUI X component. All features such as sorting, filtering, and pagination come out of the box. Under the hood it uses useList for the fetch.
optimistic-gold
optimistic-gold9mo ago
@batuhanw hi, sorry i forgot to mark this as resolved! I figured it out in the dataProvider support channel. But thanks!