I'm trying to find only users that have a specific service. Each user has an array of Services. And the match I need to find is the following:
userService.name === service.name && !user.disabled
Code below works, but has ESlint errors dealing with a param-reassignment.
export const matchUserWithService = (user, userService, service) => {
if (userService.name === service.name && !user.disabled) {
user.isMatched = true;
userService.rights = service.rights;
}
return userService;
};
export const renderServiceAdmins = (users, selectedService) => {
const usersWithService = users.filter((user) => {
user.services.map(usrSrv => matchUserWithService(user, usrSrv, selectedService));
if (user.isMatched) return user;
return false;
});
return usersWithService.map(user => user.services.map(service => service.rights.map((right) => {
if (
service.name === selectedService.name &&
lowCase(right.name) === 'admin' &&
!right.disabled
) {
return (
<li key={user.email + randId()}>
{ user.name } | <span className="info_blue">{ user.email }</span>
</li>
);
}
return null;
})));
};
Could this be refactored with .find
?
I would suggest restructuring the code, because now it relies on mutations inside of a .map
call, which could become pretty hard to reason about. I cant check that my suggested code actually works, but I think it expresses the intent of what you are trying to do more clearly.
Edit . Explanation: In short, we have a list of users where only some are relevant. That tells us we probably would want the code to start with users.filter
. The general idea is to filter out users that have admin rights for the selected service. So I tried to extract that logic into one function ( userHasAdminRightsForService
), which I implemented as a function that returns the function that we will want to use to filter the users. Because of this design, we get code that reads more like regular English: users.filter(userHasAdminRightsForService(selectedService))
instead of users.filter(user => userHasAdminRightsForService(user, selectedService))
.
Array.prototype.some
is used to check if an array has at least one element that meets some criteria. So a line like userService.rights.some(right => lowCase(right.name) === 'admin')
means that we check if at least one of the rights in userService.rights
satisfy the criteria that it should have the name 'admin'.
// given a serviceToCheckFor, return a function that checks if
// one specific user has any userService, with admin rights, that match the name of serviceToCheckFor
export const userHasAdminRightsForService = serviceToCheckFor = user => {
return user.services.some(userService =>
// name check
userService.name === serviceToCheckFor.name &&
// check if there exists a non-disabled admin right
userService.rights
.filter(right => !right.disabled)
.some(right => lowCase(right.name) === 'admin')
);
};
export const renderServiceAdmins = (users, selectedService) => {
const adminsForSelectedService = users
.filter(user => !user.disabled)
.filter(userHasAdminRightsForService(selectedService))
return adminsForSelectedService.map( admin =>
(<li key={admin.email + randId()}>
{ admin.name } | <span className="info_blue">{ admin.email }</span>
</li>)
);
};
Your code is valid, but as the rule points out , modifying or reassignment of function parameters can lead to unintended behavior.
Generally if you don't want to disable a rule completely in the .eslintrc
file but only want to suppress specific occurrence of an eslint error use one of rule-disabling comments , it also somewhat indicates you know what you are doing.
maybe you could rewrite without disabling the rule?
export const renderServiceAdmins = (users, selectedService) => {
var admins = users.reduce((serviceAdmins, user) => {
user.services
.forEach((service) =>{
if(service.name === selectedService.name) {
service.rights
.forEach((right)=> {
if( lowCase(right.name) === 'admin' && !right.disabled) {
serviceAdmins.concat[{
name: user.name,
name: user.email
}]
}
})
}
});
return serviceAdmins;
}, []);
return admins.map(admin=> {
return (
<li key={admin.email + randId()}>
{ admin.name } | <span className="info_blue">{ admin.email }</span>
</li>
);
});
};
We ended up solving it this way, much cleaner and way less code too (removed 2 functions)! Missing part was chaining filters then using .find
export const renderServiceAdmins = (users, theService) =>
users
.filter(user => !user.disabled)
.filter(user => user.services.find(
usrSrv => (
usrSrv.name === theService.name &&
usrSrv.rights.find(r => r.name.toLowerCase() === 'admin' && !r.disabled)
)
))
.map(user => (
<li key={user.email + randId()}>
{ user.name } | <span className="info_blue">{ user.email }</span>
</li>
));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.