-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
feat(Menu): Add items
shorthand
#506
Conversation
Looks like tests crashed, There are also a number of new lines added without coverage. I suspect codecov will fail unless tests are added for the red lines here: FWIW, you can see coverage info right on the PR with the codecov browser extension (shown above). Also, you can open |
renderItems() { | ||
const { items, onItemClick } = this.props | ||
|
||
this.trySetState({ activeIndex: _.findIndex(items, ['active', false]) || -1 }) |
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 don't think there should be a setState
call inside a render.
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.
Agree, moved to componentWillMount
const active = this.state.activeIndex === index | ||
const finalKey = childKey || [content, name].join('-') | ||
|
||
const handleClick = (e, { itemName, itemIndex }) => { |
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.
Prop changes generally result in a component re-rendering. Since this function is being creating new for each item each time renderItems
is called, these MenuItem
s will always be receiving new props on each render. This should probably use a similar pattern of having Menu
define a handleItemClick
callback like the Dropdown
does.
const finalKey = childKey || [content, name].join('-') | ||
|
||
const handleClick = (e, { itemName, itemIndex }) => { | ||
const handler = onItemClick || onClick |
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.
If the user passes both a Menu onItemClick
and an Item onClick
, their onClick will never be called. Instead of choosing one or the other, I think we should call each separately:
if (onClick) onClick(e, { itemName, itemIndex })
if (onItemClick) onItemClick(e, { itemName, itemIndex })
I've also called them in order here, from the Item up to the Menu.
} | ||
|
||
return <ElementType {...rest} className={classes}>{this.renderItems()}</ElementType> | ||
return <ElementType {...rest} className={classes}>{children || this.renderItems()}</ElementType> |
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.
More simple
|
||
const handleClick = (e, data) => { | ||
this.handleItemClick(e, data) | ||
if (onClick) onClick(e, data) | ||
} |
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.
If the user passes both a Menu onItemClick and an Item onClick
Fixed there, but still
Since this function is being creating new for each item each time renderItems is called, these MenuItems will always be receiving new props on each render.
What I can do there?
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.
Anything that doesn't recreate the handleClick function every loop would work. You could for instance pass the onClick
as an extra parameter to the handleItemClick
method:
this.handleItemClick(e, data, onClick)
Then, in handleItemClick
if onClick
exists, call it with the same event and data.
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'm moved condition to handleItemClick
.
handleItemClick(e, { name, index }, onClick) {
...
if (onClick) onClick(e, { name, index })
if (onItemClick) onItemClick(e, { name, index })
}
But problem will be still there, handleClick
will be created on each iteration, or not?
const handleClick = (e, data) => this.handleItemClick(e, data, onClick)
return <MenuItem onClick={handleClick} />
//
return <MenuItem onClick={(e, data) => this.handleItemClick(e, data, onClick)} />
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.
Sorry slow brain today, you are correct. It looks like if you are going to call two functions, then we'll always have to create the callback function in every loop. If we weren't calling both handleItemClick and onClick, then we could just pass handleItemClick
.
As I write this, one other idea comes to mind. You could just pass onClick={this.handleItemClick}
which will get called with the item name/index. Then, you could lookup the item in items
and call its onClick
with the same args if it exists:
handleItemClick = (e, { name, index }) => {
const { items, onItemClick } = this.props
if (_.get(items, `[${index}].onClick`)) items[index].onClick(e, { name, index })
// ...
}
I'll improve coverage and add docs soon. |
Current coverage is 98.74% (diff: 100%)@@ master #506 diff @@
==========================================
Files 106 106
Lines 1744 1753 +9
Methods 0 0
Messages 0 0
Branches 0 0
==========================================
+ Hits 1722 1731 +9
Misses 22 22
Partials 0 0
|
Updated to |
Reviewing, will merge if I can |
Just cleaned up one unused param, will merge when tests pass. |
Released in |
This PR:
Menu
in docs;items
shorthand forMenu
: