React – Function calling API uses default state parameters instead of correct state parameters

I am having trouble with the below code. This is a basic table which displays users and I am trying to implement some sort functionality however it is not working.

When running I can click the sort buttons and they will update the sortParameters state accordingly, however, the function which requests the data from the API (getUsersFromAPI) does not recognise this state change. When running this function is supposed to fetch the data and then use the reducer to sort according to the updated sortParameters, but it instead is returning the usersList as it is received from the API and the console.log(sortParameters) returns the defaultSortParameters. I am not sure why sortParameters isn’t updating in this function when a sort button is clicked?

Any help would be greatly appreciated.

Thanks,

Greg

    useState,
    useReducer,
    useEffect,
    useLayoutEffect,
    useContext,
} from "react";
import { useUser } from "../../contexts/UserContext";
import { usersListReducer } from "../../reducers/usersListReducer";
import {
    API_users_usersGetAllUsers,
    API_users_DeleteUser,
} from "../../publicFunctions/usersAPI";

// reactstrap components
import {
    Card,
    CardHeader,
    CardBody,
    CardTitle,
    Table,
    Row,
    Col,
    ButtonGroup,
    Button,
} from "reactstrap";

import NewUser from "../Users/NewUser";
import classNames from "classnames";

const defaultSortParameters = { sortType: "NAME", sortDirection: true };

const Users = () => {
    //------------------------- STATE -------------------------
    const currentUser = useUser();
    const [showNewUser, setShowNewUser] = useState(false);
    const [sortParameters, setSortParameters] = useState(defaultSortParameters);
    const [usersList, usersDispatch] = useReducer(usersListReducer, []);

    //-------------------- CLICK HANDLING ---------------------
    const deleteUser = async (id, name) => {
        //check if trying to delete self
        if (currentUser.id === id) return alert("Cannot delete self");

        //check for delete confirmation
        if (
            window.confirm("Are you sure you want to delete user " + name) === true
        ) {
            //remove user from userList if OK status is returned
            const result = await API_users_DeleteUser(id);
            if (result.statusText === "OK") {
                usersDispatch({
                    type: "DELETE_USER_BY_ID",
                    payload: id,
                });
            }
        }
    };

    //sorting by column
    const sortUsers = (sortType) => {
        setSortParameters({
            ...sortParameters,
            sortType: sortType,
            sortDirection: !sortParameters.sortDirection,
        });
        usersDispatch({
            type: "SORT",
            payload: {
                sortType: sortType,
                sortDirection: sortParameters.sortDirection,
            },
        });

        console.log(sortParameters);
    };

    //----------------------- MOUNTING ------------------------
    //get users from API when component mounts
    useEffect(() => {
        //get initial data on mount
        getUsersFromAPI();
        //set interval to refresh data periodically
        const interval = setInterval(() => {
            getUsersFromAPI();
        }, 5000);
        return () => {
            clearInterval(interval);
        };
    }, []);

    //----------------------- UPDATING ------------------------
    const newUser = () => {
        setShowNewUser(!showNewUser);
    };

    //----------------------- FUNCTIONS -----------------------
    const getUsersFromAPI = async () => {
        let result = await API_users_usersGetAllUsers();
        if (result === undefined) {
            console.log("ERROR: Cannot get users in Users.js");
        } else {
            usersDispatch({
                type: "GET_USERS_FROM_API",
                payload: result,
            });
            usersDispatch({
                type: "SORT",
                payload: {
                    sortType: sortParameters.sortType,
                    sortDirection: sortParameters.sortDirection,
                },
            });
        }
        console.log(sortParameters);
    };

    //------------------------ RENDER -------------------------
    return (
        <>
            <div className="content">
                <button onClick={() => console.log(currentUser)}>user</button>
                <button onClick={() => console.log(sortParameters)}>sort params</button>
                <Row>
                    <Col md="12">
                        <Card>
                            <Col sm="6">
                                <ButtonGroup
                                    className="btn-group-toggle float-left"
                                    data-toggle="buttons"
                                >
                                    <Button
                                        className={classNames("btn-simple", {
                                            active: showNewUser === true,
                                        })}
                                        color="info"
                                        id="0"
                                        size="sm"
                                        onClick={newUser}
                                    >
                                        New user
                                    </Button>
                                </ButtonGroup>
                            </Col>

                            <Col>
                                {showNewUser ? (
                                    <NewUser
                                        setShowNewUser={setShowNewUser}
                                        getUsersFromAPI={getUsersFromAPI}
                                    />
                                ) : (
                                    <></>
                                )}
                                <h2>Need a search Bar</h2>
                            </Col>

                            <CardHeader>
                                <CardTitle tag="h4">Users</CardTitle>
                            </CardHeader>

                            <CardBody>
                                <Table className="tablesorter" responsive>
                                    <thead className="text-primary">
                                        <tr>
                                            <th>
                                                Name{" "}
                                                <button onClick={() => sortUsers("NAME")}>sort</button>
                                            </th>
                                            <th>
                                                Email
                                                <button onClick={() => sortUsers("EMAIL")}>sort</button>
                                            </th>
                                            <th>
                                                Description
                                                <button onClick={() => sortUsers("DESCRIPTION")}>
                                                    sort
                                                </button>
                                            </th>
                                            <th>
                                                Online
                                                <button onClick={() => sortUsers("ONLINE")}>
                                                    sort
                                                </button>
                                            </th>
                                            <input type="text" />
                                        </tr>
                                    </thead>
                                    <tbody>
                                        {usersList?.map((user) => {
                                            return (
                                                <tr>
                                                    <td>{user.name}</td>
                                                    <td>{user.email}</td>
                                                    <td>{user.description}</td>
                                                    {user.is_online === false ? (
                                                        <td> false </td>
                                                    ) : (
                                                        <>
                                                            {" "}
                                                            <td>true</td>{" "}
                                                        </>
                                                    )}
                                                    <td>
                                                        <Button
                                                            className={classNames("btn-simple")}
                                                            color="info"
                                                            id="deleteUser"
                                                            size="sm"
                                                            onClick={() => deleteUser(user.id, user.name)}
                                                        >
                                                            Delete
                                                        </Button>
                                                    </td>
                                                </tr>
                                            );
                                        })}
                                    </tbody>
                                </Table>
                            </CardBody>
                        </Card>
                    </Col>
                </Row>
            </div>
        </>
    );
};

export default Users;

reducer function sort code:

case "SORT":
            //Switch by sort type
            switch (action.payload.sortType) {
                case "NAME":
                    if (action.payload.sortDirection === true) {
                        sortedUsersList.sort((a, b) => (a.name > b.name ? 1 : -1));
                        return sortedUsersList;
                    } else {
                        sortedUsersList.sort((a, b) => (a.name < b.name ? 1 : -1));
                        return sortedUsersList;
                    }
                case "EMAIL":
                    if (action.payload.sortDirection === true) {
                        sortedUsersList.sort((a, b) => (a.email > b.email ? 1 : -1));
                        return sortedUsersList;
                    } else {
                        sortedUsersList.sort((a, b) => (a.email < b.email ? 1 : -1));
                        return sortedUsersList;
                    }
                case "DESCRIPTION":
                    if (action.payload.sortDirection === true) {
                        sortedUsersList.sort((a, b) =>
                            a.description > b.description ? 1 : -1
                        );
                        return sortedUsersList;
                    } else {
                        sortedUsersList.sort((a, b) =>
                            a.description < b.description ? 1 : -1
                        );
                        return sortedUsersList;
                    }

                case "ONLINE":
                    if (action.payload.sortDirection === true) {
                        sortedUsersList.sort((a, b) =>
                            a.is_online > b.is_online ? 1 : -1
                        );
                        return sortedUsersList;
                    } else {
                        sortedUsersList.sort((a, b) =>
                            a.is_online < b.is_online ? 1 : -1
                        );
                        return sortedUsersList;
                    }
            }