i am working on an application that I make API calls to get some users for an id. the API gives you the users in an object of 25 length, and i order to get the other users u have to make other API calls.
I have a parent component from which I look for users and I pass down some variables to my child component:
<UserSection
id={id}
code={code}
open={open}
users={users}
setOpen={setOpen}
handleClose={handleClose}
handleUsers={handleUsers}
total={total}
currentPageNr={currentPageNr}
maxPageNr={maxPageNr}
/>
then in my child component I am using the material ui data grid as follows:
const [rowsState, setRowsState] = React.useState({
page: 0,
pageSize: 25,
rows: [],
loading: false,
});
const rows = [];
useEffect(() => {
let active = true;
(async () => {
setRowsState((prev) => ({ ...prev, loading: true }));
await fetchAllUsers(rowsState.page);
for (let i = 0; i < users.length; i ) {
if (users[i].campaign_id == props.id) {
let row = {
id: i 1,
col1: i 1,
col2: users[i].id,
col3: users[i].first_name,
col4: users[i].qualified,
col5: users[i].email,
col6: users[i].source,
col7: users[i].referrer_id,
col8: showName(users[i].referrer_id),
// col9: props.users[i].url,
col10: justSHowReached(users[i].id),
col11: users.filter(
(u) => u.referrer_id == users[i].id && u.qualified
).length,
col12: changeDate(users[i].date),
// col13: "",
};
rows[i] = row;
}
}
const newRows = rows;
console.log("new rows:", newRows);
console.log("eowsState.page:", rowsState.page);
// console.log("===**=== rowsState.pageSize:", rowsState.pageSize);
if (!active) {
return;
}
setRowsState((prev) => ({ ...prev, loading: false, rows: newRows }));
})();
return () => {
active = false;
};
}, [rowsState.page, rowsState.pageSize]);
and this is how I try to fetch users based on page number:
const fetchAllUsers = async (pageNumber) => {
console.log("----------------------------------");
console.log("page number: ", pageNumber);
console.log("----------------------------------");
await fetch(
`........./api/v1/users?page=${pageNumber}`,
{
method: "GET",
headers: new Headers({
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
}),
}
)
.then((res) => res.json())
.then(async (data) => {
// console.log("=================rows=================");
setUsers(data.data);
return data.data;
})
.catch((error) => {
console.log(error);
});
};
so I set my users here which I want to use on data model.
and also
const columns = [
{ field: "col1", headerName: "#", width: 50 },
{ field: "col2", headerName: "Id", width: 100, sortable: false },
{ field: "col3", headerName: "Name", width: 100 },
{ field: "col4", headerName: "Qualified", width: 100 },
{ field: "col5", headerName: "Email", width: 200 },
{ field: "col6", headerName: "Source", width: 75 },
{ field: "col7", headerName: "Referrer Id", width: 125 },
{ field: "col8", headerName: "Referrer Name", width: 125 },
// { field: "col9", headerName: "Url", width: 300 },
{
field: "col10",
headerName: "Reached",
width: 150,
},
{ field: "col11", headerName: "Qualified", width: 150 },
{ field: "col12", headerName: "Date Created", width: 150 },
{
field: "col13",
headerName: "Action",
width: 150,
sortable: false,
filterable: false,
hideable: false,
renderCell: (params) => {
const onClick = (e) => {
e.stopPropagation(); // don't select this row after clicking
const api = params.api;
const thisRow = {};
api
.getAllColumns()
.filter((c) => c.field !== "__check__" && !!c)
.forEach(
(c) => (thisRow[c.field] = params.getValue(params.id, c.field))
);
console.log("---->", thisRow.col2, thisRow.col4);
setUserId(thisRow.col2);
updateUser(thisRow.col2, thisRow.col4);
// return alert(JSON.stringify(thisRow, null, 4));
};
return (
<>
<Button variant="contained" onClick={onClick}>
update
</Button>
</>
);
},
},
];
this is how I make my model:
<DataGrid
// rows={rows}
columns={columns}
pagination
rowCount={props.total}
paginationMode="server"
// pageSize={25}
rowsPerPageOptions={[25]}
{...rowsState}
onPageChange={(page) => {
// console.log("and page is ", page);
setRowsState((prev) => ({ ...prev, page }));
}}
onPageSizeChange={(pageSize) =>
setRowsState((prev) => ({ ...prev, pageSize }))
}
/>
the problem is that I load users but I wont be able to show them inside my model
I am loading 25 users but the model doesn't show anything, however it shows me 1–25 of 5101
when i click on >
I can load the users on my model like but now I am on 26–50 of 5101
so I am in page 2 but I am showing the data for page 1, when i click on >
again I can see that this works but I am always behinds the correct page and sometimes Im in page 6 but I am still seeing data for page 2, and I can see that model is not being updated correctly.
on my dependency on my useEffect
I have [rowsState.page, rowsState.pageSize],
while the
CodePudding user response:
There's a lot going on here, and I think your component is overall too complex. If you try and simplify things you might make it easier to see the problem.
First, I'd move the fetchAllUsers
out to a separate method - it doesn't need to use state, it can just be a simple wrapper around an API call. Also, given that it's fetching a subset of users, it should probably not be called "fetchAllUsers". And, you're mixing async/await
with promises - just stick with using async/await
. Something like this might work
const fetchUsersForPage = async (pageNumber) => {
try {
const response = await fetch(
// Copied from your code but looks very suspicious...
`........./api/v1/users?page=${pageNumber}`,
{
method: "GET",
headers: new Headers({
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
}),
});
const { data } = await response.json();
return data;
} catch (error) {
console.log(error);
}
};
I'd also suggest you encapsulate the loading of the paged data into a separate hook. This article does a good job of explaining why you should use custom hooks for encapsulation. Your effect also has a dependency on the props.id
which looks like it's a campaign id. Again, something like this might work - there's a few red flags in there which I've commented in the code below:
const usePagedData = (campaignId, page, pageSize) => {
const [loading, setLoading] = useState(false);
const [rows, setRows] = useState([]);
useEffect(() => {
const loadPageData = async () => {
setLoading(true);
const users = await fetchUsersForPage(page);
const userRows = users
// This looks suspicious - you might be losing users because they
// don't match the campaign? Shouldn't you pass the campaignId
// as part of the fetch in that case?
.filter(user => user.campaign_id === campaignId)
.map((user, index) => ({
id: index 1,
col1: index 1,
col2: user.id,
col3: user.first_name,
col4: user.qualified,
col5: user.email,
col6: user.source,
col7: user.referrer_id,
// Not sure what these functions are??
col8: showName(user.referrer_id),
// col9: props.users[i].url,
col10: justSHowReached(user.id),
// This number will almost certainly be wrong since 'users' is
// the list of users for this page.
col11: users.filter(u => u.referrer_id == user.id && u.qualified).length,
col12: changeDate(user.date),
// col13: "",
}));
setRows(userRows);
}
loadPageData();
}, [campaignId, page, pageSize]);
return {
rows,
loading
}
}
Now your component that contains the data grid can use your custom hook as follows:
const { rows, loading } = usePagedData(props.id, page, pageSize);