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

[Enhancement] Add menuComponent option for custom Menu rendering. #763

Closed
wants to merge 1 commit into from

Conversation

Craga89
Copy link

@Craga89 Craga89 commented Feb 8, 2016

Currently there's no easy way to override the Menu component used internally, in a similar way to the Option and Value components.

This is handy especially in cases where we want to implement, say, a virtualized scrolling approach when rendering a large amount of items (#738, #554) using react-virtualized or react-list. It's may also be a possible opportunity to implement react-tether to position the menu dynamically based on viewport constraints (#637, #697).

I've added new example to the examples files that implements the aforementioned react-virtualized approach to render a large list of 300 items (also included).

@Craga89
Copy link
Author

Craga89 commented Feb 8, 2016

Doh, accidentally included the dist files in this PR. Would you like me to re-PR once I've fixed?

[Edit] Aaaaand I forgot to lint... should not PR late at night

@JedWatson
Copy link
Owner

Hey @Craga89, thanks for this!

Sounds great, would you mind updating the PR just to include the changes to the src files? hard to review the diff with everything included. I'll update the build & release a new version once it's merged.

@Craga89
Copy link
Author

Craga89 commented Feb 27, 2016

Rebased with just the src and example file changes, sorry for the delay :)

@Craga89
Copy link
Author

Craga89 commented Feb 27, 2016

Rebased into single commit with only the src and example files changed and pulled from master, too 👍

className="Select-menu"
style={this.props.menuStyle}
onScroll={this.handleMenuScroll}
onMouseDown={this.handleMouseDownOnMenu}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Looks like you have an extra > ?

@cloudkite
Copy link
Contributor

@Craga89 are you still able to work on this? If you don't have the capacity, I'm happy to contribute a pull request instead as it's becoming an urgent requirement at work. I think @bvaughn was interested in spending some effort on it as well. Let me know thanks :)

@Craga89
Copy link
Author

Craga89 commented Mar 26, 2016

Added the missing files, removed the syntax error and rebased onto current master :)

Also added new example that implements react-virtualized to render
a large list of 300 items, with virtualized scrolling for perf.
@coveralls
Copy link

Coverage Status

Changes Unknown when pulling cbe2233 on Craga89:master into * on JedWatson:master*.

@cloudkite
Copy link
Contributor

@Craga89 nice work 👍 really hoping this gets merged @bvaughn you mentioned in #808 (comment) that you feel that creation of children should be given over to react-virtualized using a factory function or something similar. My understanding is that ReactElements are fairly cheap to create (the expensive part is attaching and rendering them to the DOM) so this PR should get us most of the way. Maybe functionality to provide a factory function for creating options could be a seperate PR as a further optimisation for scenarios when you have very very long list of data and don't want the overhead of creating a whole bunch of ReactElements upfront.

@bvaughn
Copy link
Collaborator

bvaughn commented Mar 29, 2016

@Craga89: React elements do seem cheap to create but it still wastes cycles to create them unnecessarily. The main reason I mentioned this is that react-virtualized integration was mentioned on this PR (and a related issue) and that requires the ability to manage/defer the creation of children. :)

@Craga89
Copy link
Author

Craga89 commented Mar 29, 2016

@bvaughn @cloudkite Agreed, it's somewhat of a "bodge" in that sense but really this PR is just to give a general way to replace the menuComponent wholesale without worrying about specifics, inline with similar props the plugin provides.

We're using the approach mentioned here at work using react-virtualized to render 600+ items and it's usable, but could definitely benefit from the deferred approach. I'll take another pass at it soon if I get time at work.

@cloudkite
Copy link
Contributor

@Craga89, @bvaughn I would advocate trying to get this merged as it is now if @JedWatson is happy with the changes so far. Since its a workable solution for relatively large lists and solves other issues mentioned such as dynamic menu positioning. Then in future another seperate PR could be raised to implement deferred creation of menu options to allow further optimisation, thoughts?

@bvaughn
Copy link
Collaborator

bvaughn commented Mar 29, 2016

Incremental changes are good :) I have no objections. (It's up to Jed really.) I am still happy to help with a react-virtualized integration if there's interest. (Happy to do it if it's likely to get merged, would rather not invest a bunch of time if it's unlikely to get merged.)

@bvaughn
Copy link
Collaborator

bvaughn commented Mar 31, 2016

Hi again. :) I created a fork of react-select this evening and tried integrating react-virtualized just to see how difficult it would be. In case you're curious...

My fork is obviously a direct integration but it was just intended as a proof of concept. I feel pretty confident about an integration between these 2 libraries now that I've kind of played with it a bit more, but I have one pretty important change I would recommend making. Rather than passing in a pre-rendered menuComponent- pass in a custom renderMenu function that received named parameters. Then inside of the existing renderMenu you could do something like this:

renderMenu (options, valueArray, focusedOption) {
  if (this.props.renderMenu) {
    // This can return a VirtualScroll (or anything else for that matter).
    return this.props.renderMenu({
      focusedOption,
      focusOption: this.focusOption,
      options,
      selectValue: this.selectValue,
      valueArray
    });
  } else {
    // This can return the default, non-virtualized menu.
  }
}

This would allow you to avoid unnecessarily creating all of the children and tossing away that benefit of react-virtualized. What do you think, @Craga89 and @cloudkite?

All that being said, I would be happy to release and maintain an adapter library that sits between react-select and react-virtualized for users who want to enable virtualization by going this route. (I've already reserved an NPM package for this purpose in fact.)

@bvaughn
Copy link
Collaborator

bvaughn commented Mar 31, 2016

FWIW I went ahead and tried what I suggested in my own branch.

I think this is the direction to go. I'd be happy to submit a PR (or a patch to this PR) if there's interest.

@bvaughn
Copy link
Collaborator

bvaughn commented Mar 31, 2016

FYI I went ahead and submitted a PR with the approach I outlined for easier discussion purposes ~ #859

@Craga89
Copy link
Author

Craga89 commented Apr 2, 2016

Great job @bvaughn, that looks much more flexible than this approach. Happy to close this if everyone agrees? Though, perhaps having a menuComponent prop serves a simpler use case that could live side-by-side?

@bvaughn
Copy link
Collaborator

bvaughn commented Apr 2, 2016

Thank you @Craga89! Fwiw I also released a HOC to make the integration between the 2 libraries easier: https://github.com/bvaughn/react-virtualized-select/

Maybe that helps address your concerns about "simpler use case"?

@Craga89
Copy link
Author

Craga89 commented Apr 3, 2016

Perfect! I'll be using that come Monday! Closing ^_^

@Craga89 Craga89 closed this Apr 3, 2016
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.

5 participants