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

feat(Menu): Add items shorthand #506

Merged
merged 7 commits into from
Sep 20, 2016
Merged

feat(Menu): Add items shorthand #506

merged 7 commits into from
Sep 20, 2016

Conversation

layershifter
Copy link
Member

@layershifter layershifter commented Sep 17, 2016

This PR:

  • Resolved old TODOs for Menu in docs;
  • Adds items shorthand for Menu:
const items [
  {name: 'Open'},
  {name: 'Save'},
]

<Menu items={items} onItemClick={handler} />
const items [
  {name: 'Open', onClick: onOpenClick},
  {active: true, name: 'Save', onClick: onSaveClick},
]

<Menu items={items} />

@levithomason
Copy link
Member

Looks like tests crashed, Maximum call stack exceeded. I've retried tests without cache to see if it resolves the issue.

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:

image

FWIW, you can see coverage info right on the PR with the codecov browser extension (shown above). Also, you can open /coverage/lcov-report/index.html and drill down into specific coverage info.

renderItems() {
const { items, onItemClick } = this.props

this.trySetState({ activeIndex: _.findIndex(items, ['active', false]) || -1 })
Copy link
Member

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.

Copy link
Member Author

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 }) => {
Copy link
Member

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 MenuItems 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
Copy link
Member

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>
Copy link
Member Author

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)
}
Copy link
Member Author

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?

Copy link
Member

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.

Copy link
Member Author

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

Copy link
Member

@levithomason levithomason Sep 19, 2016

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 })
  // ...
}

@layershifter
Copy link
Member Author

There are also a number of new lines added without coverage.

I'll improve coverage and add docs soon.

@codecov-io
Copy link

codecov-io commented Sep 19, 2016

Current coverage is 98.74% (diff: 100%)

Merging #506 into master will increase coverage by <.01%

@@             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          

Powered by Codecov. Last update fa64096...186eada

@layershifter
Copy link
Member Author

Updated to master, seems we ready to go.

@levithomason
Copy link
Member

Reviewing, will merge if I can

@levithomason
Copy link
Member

Just cleaned up one unused param, will merge when tests pass.

@levithomason levithomason merged commit bce49c9 into master Sep 20, 2016
@levithomason levithomason deleted the feat/menu-shorthand branch September 20, 2016 15:39
@levithomason
Copy link
Member

Released in stardust@0.44.9, thanks much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants