Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the same component to render every app icon #655

Merged
merged 3 commits into from
Mar 20, 2019
Merged

Conversation

bpierre
Copy link
Contributor

@bpierre bpierre commented Mar 19, 2019

Use a single component for app icons: AppIcon.

  • This component replaces RemoteIcon and Permissions/AppIcon.
  • Manages displays the app icon or the default, based on the appId.
  • Accepts an src parameter too (useful for the Apps screen).
  • The radius is automatic but can also be set independently from the size.

Also fixes the home icon alignment on Chrome.

image

@bpierre bpierre requested review from sohkai and AquiGorka March 19, 2019 17:18
import IconHome from './icons/app-home.svg'
import IconHomeSvg from './icons/app-home.svg'

const IconHome = () => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should place this in the icons directory?

Copy link
Contributor Author

@bpierre bpierre Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went a bit farther and refreshed the way we manage app icons in general: edfc2cf

- This component replaces RemoteIcon and Permissions/AppIcon.
- AppIcon manages displays the app icon or the default, based on the appId.
- AppIcon accepts an `src` parameter too (useful for the Apps screen).
- The radius is automatic but can also be set independently from the
  size.
@bpierre bpierre changed the title Fix the Home icon on Chrome Add AppIcon to render every app icon Mar 20, 2019
@bpierre bpierre requested a review from sohkai March 20, 2019 01:40
@bpierre bpierre changed the title Add AppIcon to render every app icon Use AppIcon to render every app icon Mar 20, 2019
@bpierre bpierre changed the title Use AppIcon to render every app icon Use the same component to render every app icon Mar 20, 2019
@@ -19,7 +19,20 @@ class AppInstanceLabel extends React.PureComponent {
<Main>
<Viewport>
{({ above }) =>
above('medium') && showIcon && <AppIconInRow app={app} />
above('medium') &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just started wondering if I should use above('medium') instead of !below('medium')

`}
{...props}
>
{(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow!
Would it have been cleaner to use another component instead of a self executing function?

Copy link
Contributor Author

@bpierre bpierre Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I don’t have any preference for one or the other (until we have pattern matching 💥), I tend to use this pattern because I find it more readable than using nested ternary operators, and declaring + calling a function at render time is something we do a lot with render props, so I don’t think it is an issue performance wise (as long as we don’t render at 60FPS!).

Having internal components is nice too, but the problem is that ESLint insists that every component requires prop types, which makes it super verbose. I couldn’t find any setting to only apply this rule to exported components.

Maybe we could directly call functions for this? That would also skip the extra step of creating a React element + having React calling it (insignificant gain in most cases, but it can be an argument to decide).

function MyComponent(props) {
  return (
    <div>
      {myComponentContent(props)}
    </div>
  )
}

function myComponentContent({ a, b }) {
  if (a) {
    return <span>{a}</span>
  }
  if (b) {
    return <span>{b}</span>
  }
  return <span>default</span>
}

Another solution would be to disable this rule after the main component, which would make it possible to have light internal components:

function MyComponent(props) {
  return (
    <div>
      <MyComponentContent {...props} />
    </div>
  )
}

MyComponent.propTypes = { /* … */ }

// Disabling the ESLint prop-types check for internal components.
/* eslint-disable react/prop-types */

function MyComponentContent({ a, b }) {
  if (a) {
    return <span>{a}</span>
  }
  if (b) {
    return <span>{b}</span>
  }
  return <span>default</span>
}

And for simple cases, I think the “IIFE in JSX” pattern, while not being the most elegant thing in the world, can do a good job too 😆

function MyComponent({ a, b }) {
  return (
    <div>
      {(() => {
        if (a) {
          return <span>{a}</span>
        }
        if (b) {
          return <span>{b}</span>
        }
        return <span>default</span>
      })()}
    </div>
  )
}

@AquiGorka @sohkai I don’t really have any preference, I think the three solutions are fine and I use them depending on the context. I pushed #2 for now as @AquiGorka was suggesting a preference for it rather than #3. Let me know if you have any opinion about it so we align!

EDIT:

Adding a few other possibilities for the sake of completeness:

Mutable variable (no early returns 😩):

function MyComponent({ a, b }) {
  let content = <span>default</span>
  if (a) {
    content = <span>{a}</span>
  }
  if (b) {
    content = <span>{b}</span>
  }
  return (
    <div>
      {content}
    </div>
  )
}

Wrapping function:

function MyComponent({ a, b }) {
  const wrap = content => <div>{content}</div>
  if (a) {
    return wrap(<span>{a}</span>)
  }
  if (b) {
    return wrap(<span>{b}</span>)
  }
  return wrap(<span>default</span>)
}

Nested ternary:

function MyComponent({ a, b }) {
  return (
    <div>
      {a ? (
        <span>{a}</span>
      ) : b ? (
        <span>{b}</span>
      ) : (
        <span>default</span>
      )}
    </div>
  )
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ @bpierre thank you for taking the time to explain your line of thinking and yes I prefer #2 but it is only a personal preference and I can adhere to any team convention we agree on - and yes, because of prop types it becomes a bit too verbose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool :-) Let’s not make it a convention for now then, and we can refer to this discussion if we want to avoid one of these patterns in the future!

Copy link
Contributor

@AquiGorka AquiGorka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ Thank you! For a minute I thought I introduced the bug in chrome...

Copy link
Contributor

@sohkai sohkai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

if (src) {
return <IconBase size={size} src={src} />
}
if (!app) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could remove this condition if we flip it to be if (app)

@bpierre bpierre merged commit a79d595 into master Mar 20, 2019
@bpierre bpierre deleted the fix-home-icon branch March 20, 2019 12:58
2color added a commit that referenced this pull request Apr 3, 2019
* origin/master: (56 commits)
  Identity - Improve LocalIdentityBadge (#673)
  Menu panel footer separator (#666)
  fix(MenuPanel): avoid clickable margin above system apps toggle (#671)
  Local identities (#656)
  MenuPanel: add toggle animation to show/hide system apps (#658)
  Add github workflow for linting/building (#663)
  Permissions: added system and background app labels (#650)
  Use the same component to render every app icon (#655)
  chore: add all contributors and contributing guidelines (#649)
  Manage the menu button using messages + prevent re-mounting on resize (#651)
  Update melon (#647)
  Apps <> System apps separator (#648)
  Upgrade lint-staged (#646)
  fix: always leave Kernel as first app (#645)
  fix: avoid assigning a registry tag if app is not on a registry (#644)
  chore: upgrade @aragon/wrapper to v4.0.0-beta.1 (#639)
  DaoSettings: add bottom margin on app items (#638)
  Refactor common components (#615)
  Enforce MenuPanel’s width (#636)
  Menu panel swipe open close (#606)
  ...
2color added a commit that referenced this pull request Apr 3, 2019
* origin/master: (55 commits)
  Identity - Improve LocalIdentityBadge (#673)
  Menu panel footer separator (#666)
  fix(MenuPanel): avoid clickable margin above system apps toggle (#671)
  Local identities (#656)
  MenuPanel: add toggle animation to show/hide system apps (#658)
  Add github workflow for linting/building (#663)
  Permissions: added system and background app labels (#650)
  Use the same component to render every app icon (#655)
  chore: add all contributors and contributing guidelines (#649)
  Manage the menu button using messages + prevent re-mounting on resize (#651)
  Update melon (#647)
  Apps <> System apps separator (#648)
  Upgrade lint-staged (#646)
  fix: always leave Kernel as first app (#645)
  fix: avoid assigning a registry tag if app is not on a registry (#644)
  chore: upgrade @aragon/wrapper to v4.0.0-beta.1 (#639)
  DaoSettings: add bottom margin on app items (#638)
  Refactor common components (#615)
  Enforce MenuPanel’s width (#636)
  Menu panel swipe open close (#606)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants