-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Improve Expensicon lib #1188
Improve Expensicon lib #1188
Conversation
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
Okay, this is ready for another round of review. I separated out brand assets from Expensicons. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM and tests well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great overall. Just have a few style notes and minor ideas.
src/components/Icon/index.js
Outdated
const ICONS = _.extend(BRAND_ASSETS, EXPENSICONS); | ||
|
||
const propTypes = { | ||
icon: PropTypes.oneOf(_.values(ICONS)).isRequired, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate this but I think this could just be validated that it's some kind of component rather than need to validate that it's one of the large list of icon components and it would simplify this a bit.
src/components/Icon/index.js
Outdated
Icon.propTypes = propTypes; | ||
Icon.defaultProps = defaultProps; | ||
|
||
export default memo(Icon); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason we might want to prevent this component from re-rendering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose for memoizing the component was to boost performance. Icons will render often (and almost always with the same props), so this seems like the classic use-case for React.memo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds reasonable to me. I just have a few questions...
Icons will render often
I'm wondering if this will always be the case? Maybe some icons will not render often? And even if they did... is it expensive to render an SVG? Said another way, is there some specific performance issue that we are trying to prevent? Should we just wrap all the things in React.memo()
in that case? Is there any reason why we might want to use React.memo()
judiciously? Or is it no big deal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's an article that provides some pretty good insight on when it is and is not a good idea to use React.memo
. This diagram summarizes the heuristic pretty well:
As far as I understand, it's a balancing act between the time it takes to compare the props for equality vs the time it takes for the component to render. I think if you had a component with no props (unlikely, but possible), then you would always want to use React.memo
, because the equality comparison is close to instantaneous.
The Icon
component for sure meets the first three criteria in the diagram above, and it's a bit of a toss-up whether or not it meets the third. I have no idea how to measure and know for sure. Probably not a significant difference either way, but maybe @tgolen would have a good 6th sense as to whether or not this is a good time to use React.memo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for sharing this. I read the article and the impression I have goes something like...
If the time it takes to perform a React.memo()
shallow comparison is greater than the time it takes to render a component then we might actually be slowing things down by using React.memo()
?
The author does mention to use profiling tools to measure the benefits which sounds like a smart idea, but I might not pull them out in the first place unless something seemed slow.
So, I guess I'm sort of in the camp that we should use memo
, PureComponent
, etc when it is very clear why they are being used, there is some measurable benefit, and if we do not use them performance will degrade in an obvious way.
That said, if there is no measurable benefit in the other direction and the component still does what it's supposed to maybe it doesn't matter? At least one person in this SO post said you should "always" use it so I really don't know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also whatever we decide we should turn this into a SO post bc this is a good chat.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, agreed. I want to wait to see what Tim G has to say about it.
Just to double check here, are have you converted all of the icons into svgs here? I don't think so but wanted to check. I think the outstanding list is something like:
I'm happy to provide all of those assets for you in .svg format if you want to get them into this PR. |
Before jumping into the code in this PR, I'd like to take a step back because I think this is missing a problem statement. What is the problem being solved here? Has it been documented and confirmed? Is it enough of a problem that it requires refactoring? Understanding that will help me to go into the code with the right context, but at this point, I am not sure why these changes are necessary. |
@tgolen So high-level the problem solved by this PR is something like this: In its current form, the This PR solves that problem by creating a reusable component for icons of different types. Icon assets are collected into their own file, so adding a new icon is as simple as adding the asset to |
@shawnborton happy to include all the other assets too - should be pretty simple |
Here ya go: IconsForRory.zip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SVG and reusable component refactor ❤️
Few minor points to discuss
Any final comments @shawnborton ? |
# Conflicts: # src/components/CreateMenu.js # src/pages/home/sidebar/SidebarLinks.js
6ee53f0
e6a7727
Okay, simplified and updated to only deal with Expensicons and not brand assets for now. |
Details
This just improves the scalability of the Expensicon lib
Fixed Issues
https://github.com/Expensify/Expensify/issues/151818
Tests
Just regression test each platform to make sure that
.svg
assets still work as they should.Tested On
Screenshots
Web
Mobile Web
Desktop
iOS
Android