i created a simple pagingation in react and using JSONPlaceHolder fake API. the given data shown in material UI components. for the pagination, i use material UI component.
but there is a problem, which is when i change the page number, i have to click twice on it to appear the data in the table.
i use useState and setState will execute and we have to see rerender, but it doesn’t. all codes is in App.jsx.
even i cant use next and previous button in pagination component.
function App() {
const [users, setUsers] = useState([]);
const [slicedUsers, setSlicedUsers] = useState([]);
const countPerPage = 5;
const [currentPage, setCurrentPage] = useState(1);
const [firstIndex, setFirstIndex] = useState(0);
const [lastIndex, setLastIndex] = useState(countPerPage);
const [allPageCount, setAllPageCount] = useState(0);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then((res) => res.json())
.then((users) => {
setUsers(users);
setSlicedUsers(users.slice(firstIndex, lastIndex));
setAllPageCount(Math.floor(users.length / countPerPage));
setIsLoading(false);
});
}, []);
const paginationController = (e, value) => {
setCurrentPage(value);
setLastIndex(currentPage * countPerPage);
setFirstIndex(lastIndex - countPerPage);
setSlicedUsers(users.slice(firstIndex, lastIndex));
};
return (
<>
<Container
sx={{
display: "flex",
flexDirection: "column",
gap: "10px",
height: "100svh",
justifyContent: "center",
alignItems: "center",
}}
>
{isLoading ? (
<>
<CircularProgress color="warning" />
</>
) : (
<>
<TableContainer
component={Paper}
sx={{ boxShadow: "0 0 12px #15544b" }}
>
<Table>
<TableHead>
<TableCell>ID</TableCell>
<TableCell>Title</TableCell>
<TableCell>Body</TableCell>
</TableHead>
<TableBody>
{slicedUsers &&
slicedUsers.map((user) => (
<TableRow key={user.id}>
<TableCell>{user.id}</TableCell>
<TableCell>{user.title}</TableCell>
<TableCell>{user.body}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<Pagination
count={allPageCount}
color="primary"
hideNextButton
hidePrevButton
onChange={paginationController}
/>
</>
)}
</Container>
</>
);
}```
2
Answers
That’s because
firstIndex
andlastIndex
are not initialized withReact.useState
, therefore the component doesn’t rerender. You can’t do:Your usage of
currentPage
is correct, so do the same. Change the syntax to the following:Full working code:
To add to the excellent answer of Mike K:
you can also utilize
useEffect
to make changes incurrentPage
and re-slice theusers
array whenever the page changes:by adding another
useEffect
hook, thecurrentPage
state change triggers the effect, and handles slicing the data accordingly.doing this we have to remove the direct calls to
setSlicedUsers
from bothpaginationController
and thefetch
effect to avoid duplicates.the whole code: