James Gee
James Gee

Reputation: 139

Fetching param.id data from front to backend - React / Node / Express

I am trying to return a user list on a component from my backend and I am having trouble passing my userID param back. I am using useEffect to pull the data from Redux then call an action on the component with what I think is the declared param. The correct userID is being passed correctly as far as I can see however I think the error is occuring when the route is passed the param.

In my action how should I pass the param of the userID that I want to get the data for? I have console.log the param.id/param.userID/userID etc. In the component I have the user.userID (from useSelector) however in the action folder I don't know how to pass it to the backend.

Also in the backend do I always have to set my params as id? can these have the same name as the value on the front-end such as 'userID'? I can only seem to get the backend Postman calls working with :id.

![image|690x249](upload://acH5vA0ni6ClNNGOWwGE7mHhfYH.png)

component

const user = useSelector(state => state.auth.user);

    const [userDiveLog, setUserDiveLog] = useState({
        user: [],
        userDiveLogList: [],

        expanded: false
    })

    // get access to dispatch
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(fetchUserDiveLog(user.userID));
    }, []);

action

// pulls the user dive log
export function fetchUserDiveLog(params, credentials, diveLogUserList){
    return function(dispatch){
        return axios.get("http://localhost:5002/api/divelog/userdiveloglist/" + params.userID)
            .then(({data}) => {
                dispatch(userDiveLogList(data));
            });
    };
}

Backend

route

//  return an individual dive log
    app.get('/api/divelog/userdiveloglist/:userID', controller.userDiveLog);

controller

exports.userDiveLog = (req, res, params, userID) => {

    try {
        const userID = req.params.userID

        diveLog.findAll({
            include: {all: true},
            where: {diverUserNumber: userID}
        })
            .then(diveLog => {
                const userDiveLogList = [];
                for (i = 0; i < diveLog.length; i++) {
                    userDiveLogList.push(diveLog[i].dataValues);
                }
                if (!userDiveLogList) {
                    return res.status(404).send({message: "No dive logs belonging to this user"});
                }
                res.status(200).send({
                    data: userDiveLogList
                })
            })
    } catch(err) {
            res.status(500).send({
                message: "Error retrieving dive log belonging to user id= " + id
            });
        }
};

Upvotes: 0

Views: 2037

Answers (2)

Arun Kumar Mohan
Arun Kumar Mohan

Reputation: 11915

Frontend

You're passing the user id (user.userID - a string) to the fetchUserDiveLog function but you're treating it like a params object with the userID property inside the function. params.userID returns undefined since params is a string (it holds the user id). Rename params to userId and add it to the URL.

You can also remove the credentials and diveLogUserList arguments from the fetchUserDiveLog function since they aren't used.

export function fetchUserDiveLog(userId) {
  return (dispatch) => {
    return axios
      .get(`http://localhost:5002/api/divelog/userdiveloglist/${userId}`)
      .then(({ data }) => {
        dispatch(userDiveLogList(data))
      })
  }
}

Btw, you shouldn't hardcode the API URL. Use environment variables. If you're using Create React App, you can add environment variables prefixed with REACT_APP_ to .env or you can use dotenv-webpack if you have a custom Webpack setup.

Backend

There are a few issues with the backend code.

  1. The userDiveLog function receives the next function as the third argument but it is named params which is confusing. Since you don't need the next function in the request handler, you should remove the params and userID arguments from the function. You can get access to userID from the req.params object which you're doing correctly.
exports.userDiveLog = (req, res) => {
  // ...
}
  1. The if (!userDiveLogList) condition will never be true since userDiveLogList is an array which is truthy in JavaScript. You can actually remove the if block. A response of { data: [] } will be sent if the user doesn't have any Divelogs which is perfectly okay. You can also omit the status(200) call since the status is automatically set to 200. And you can refactor the code by using object destructuring and Array.prototype.map to transform the divelogs.
const { userID } = req.params

const diveLogs = await diveLog.findAll({
  include: { all: true },
  where: { diverUserNumber: userID },
})

const data = diveLogs.map((log) => log.dataValues)
res.send({ data })
  1. The catch block references the variable id which isn't defined anywhere. It should be userID instead.

The whole code using async/await:

exports.userDiveLog = async (req, res) => {
  const { userID } = req.params
  try {
    const diveLogs = await diveLog.findAll({
      include: { all: true },
      where: { diverUserNumber: userID },
    })
    const data = diveLogs.map((log) => log.dataValues)
    res.send({ data })
  } catch () {
    res.status(500).send({
      message: `Error retrieving dive log belonging to user id= ${userID}`,
    })
  }
}

Upvotes: 1

SNikhill
SNikhill

Reputation: 504

I have identified two questions after reading the description and I am going to answer each of those at a time.

Do I have to set the query parameter as Id?

No, there are no restrictions on the name of query parameter. You can literally name it as "something". That said, there are some conventions and those dictate that you need to name the parameter to something that is appropriate.

How do I pass userId to my Action Creator?

First of all check the Function that is wrapping your Thunk. It expects 3 parameters: params (POORLY NAMED), credentials and diveLogUserList. Where as, it is being dispatched with only 1 argument: userID.

Reconfigure this Wrapper Function to just receive the userID as an argument (and send credentials, diveUserList as an extra argument to the Thunk and not the wrapper function; This depends upon the functionality that you desire which is not properly understandable using the Description that you have provided).

After you reconfigured the wrapper function, you will dispatch the same like this: fetchUserDiveLog(userID).

The Function handling your Route is incorrect

If I am not mistaken, controller.userDiveLog should only receive 3 arguments yet, you have defined your handler with 4 parameters.

The arguments that your handler should expect are: request, response and next.

The User ID that your handler expects will be a query parameter and will be accessible using: request.params.userID.

There is no need to expect userID as an argument to your handler.

Additional Information

I recommend going through these to get a better explanation and along with that, I recommend use of console.log as a method to debug the code. It will help you identify problems such as:

  • How many arguments is this function receiving?
  • What is the type of the argument received?
  • And much more

References

Upvotes: 1

Related Questions