Issue
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.
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
});
}
};
Solution
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.
- The
userDiveLog
function receives thenext
function as the third argument but it is namedparams
which is confusing. Since you don’t need thenext
function in the request handler, you should remove theparams
anduserID
arguments from the function. You can get access touserID
from thereq.params
object which you’re doing correctly.
exports.userDiveLog = (req, res) => {
// ...
}
- The
if (!userDiveLogList)
condition will never be true sinceuserDiveLogList
is an array which is truthy in JavaScript. You can actually remove theif
block. A response of{ data: [] }
will be sent if the user doesn’t have anyDivelog
s which is perfectly okay. You can also omit thestatus(200)
call since the status is automatically set to200
. And you can refactor the code by using object destructuring andArray.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 })
- The
catch
block references the variableid
which isn’t defined anywhere. It should beuserID
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}`,
})
}
}