【问题标题】:How to fix this ESlint (no-param-reassign) error in my Filter如何在我的过滤器中修复此 ESlint (no-param-reassign) 错误
【发布时间】:2017-09-08 16:31:19
【问题描述】:

我正在尝试仅查找具有特定服务的用户。每个用户都有一系列服务。我需要找到的匹配如下:

userService.name === service.name && !user.disabled

下面的代码可以工作,但在处理参数重新分配时出现 ESlint 错误。


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;
  })));
};

这可以用.find重构吗?

【问题讨论】:

  • You're not doing anything really weird。为什么不在 .eslintrc 文件中关闭规则?
  • @Andy 因为我们需要超前到 eslint :(
  • 我明白了。我不是在谈论摆脱 ESLint,而只是关闭no-param-reassign 的规则。例如,如果我遇到这个错误,我会关闭它,因为我认为它对我来说不是特别有用。 ESLint 只是根据您的意愿选择。
  • 规则的文档有一个代码示例jsfiddle.net/baconpat/yZPj8,调试起来会很棘手。这似乎是一种边缘情况。但在这种情况下,我认为代码无论如何都可以从一些重组中受益(这将消除 lint 错误)。
  • 我可能遗漏了一些明显的东西,但不是分配给参数,你不能让它起作用并克隆userService 并返回修改后的克隆吗?它是一个昂贵的对象吗?

标签: javascript reactjs eslint higher-order-functions


【解决方案1】:

我建议重构代码,因为现在它依赖于 .map 调用内部的突变,这可能变得很难推理。我无法检查我建议的代码是否真的有效,但我认为它更清楚地表达了你想要做的事情的意图。

编辑。说明:简而言之,我们有一个用户列表,其中只有一些是相关的。这告诉我们我们可能希望代码以users.filter 开头。一般的想法是过滤掉对所选服务具有管理员权限的用户。因此,我尝试将该逻辑提取到一个函数 (userHasAdminRightsForService) 中,我将其实现为一个函数,该函数返回我们想要用来过滤用户的函数。由于这种设计,我们得到的代码读起来更像普通英语:users.filter(userHasAdminRightsForService(selectedService)) 而不是users.filter(user =&gt; userHasAdminRightsForService(user, selectedService))

Array.prototype.some 用于检查数组是否至少有一个元素满足某些条件。所以像userService.rights.some(right =&gt; lowCase(right.name) === 'admin') 这样的行意味着我们检查userService.rights 中的至少一个权限是否满足它应该具有名称“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>)
  );
};

【讨论】:

    【解决方案2】:

    您的代码有效,但as the rule points out,修改或重新分配函数参数可能会导致意外行为。

    一般来说,如果您不想完全禁用 .eslintrc 文件中的规则,而只想抑制特定的 eslint 错误发生,请使用 rule-disabling comments 之一,这在某种程度上也表明您知道自己在做什么。

    【讨论】:

      【解决方案3】:

      也许你可以在不禁用规则的情况下重写?

      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>
                );
          });
      };
      

      【讨论】:

      • 谢谢,但我试图用函数式风格来简化代码,这似乎很难理解
      • 对不起。没有提到要重写为功能样式。这解释了我猜的规则。那么另一个答案就是您要寻找的答案。
      【解决方案4】:

      我们最终以这种方式解决了它,更简洁,代码也更少(删除了 2 个函数)! 缺少的部分是链接过滤器然后使用.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>
          ));
      

      【讨论】:

      • 很高兴你找到了一些有用的东西!现在,不要成为那个人.. 但这似乎与我建议的代码完全相同,但过滤器 lambda 是内联的,而不是作为命名函数提取的。 (并使用.find 而不是.some。)公平地说我的答案中的信息解决了您的问题吗?或者相似之处仅仅是巧合? (并不是说这不可能发生)。
      猜你喜欢
      • 1970-01-01
      • 2019-10-30
      • 2021-01-09
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 2016-01-08
      • 1970-01-01
      • 2019-03-18
      相关资源
      最近更新 更多