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

choo components #639

Merged
merged 22 commits into from
Mar 30, 2018
Merged

choo components #639

merged 22 commits into from
Mar 30, 2018

Conversation

yoshuawuyts
Copy link
Member

Replacement for #606. Thanks!

@yoshuawuyts yoshuawuyts mentioned this pull request Mar 7, 2018
index.js Outdated
state.cache = renderComponent

function renderComponent (Component, id) {
assert.equal(typeof Component, 'function', 'choo-component-preview: Component should be type function')
Copy link
Member

Choose a reason for hiding this comment

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

I guess this is no longer a preview right?

assert.equal(typeof state, 'object', 'ChooComponentCache: state should be type object')
assert.equal(typeof emit, 'function', 'ChooComponentCache: state should be type function')

this.cache = lru || new LRU(100)
Copy link
Member

Choose a reason for hiding this comment

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

An LRU cache would start evicting components that are still on the page if you have a lot of them (eg. 120). I think components that are still mounted should always stay in the cache. Maybe we can have two caches, one plain object .mounted, and one LRU (or user provided) .unmounted. Then we can use on-load to move components into the unlimited .mounted cache on load, and move them to the bounded .unmounted cache on unload.

Copy link
Member

Choose a reason for hiding this comment

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

simpler is probably better, and i like your suggestion @goto-bus-stop, but here's one other idea: i wonder if it makes sense to have separate caches per component class? i guess it would just be nice not to thrash header/footer/button singleton components if an app happens to have like 1000 tweet component instances...

Copy link
Member

Choose a reason for hiding this comment

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

That would help too! Id still be worried about the tweets though. as I understand it a list of 100+ tweets would end up recreating and evicting instances during every render even if their content didn't change...

Copy link
Member

Choose a reason for hiding this comment

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

The onload idea might be pretty difficult to implement in a generic way, though, I'm not sure.

Copy link
Member Author

Choose a reason for hiding this comment

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

Id still be worried about the tweets though

If people are thinking of creating lots and lots of elements, we could recommend they create a separate cache for this specifically. If we expose the cache instance, they'll have the flexibility of choosing elements and such.

Copy link
Member

@tornqvist tornqvist Mar 13, 2018

Choose a reason for hiding this comment

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

+1 on what @yoshuawuyts said but to make that easier couldn't we allow for the third argument (lru) to be a number and forward that to nanocache? So if you don't have any preference as to what lru cache to use, but just want to allow for a lot of instances you'd do

var manyTweetsCache = new ComponentCache(state, emit, 250)

Also, most classes in the choo stack allows you to create instances without new using an instanceof check and calling new for you if needed. To maintain a uniform api, shouldn't we do that here as well?

module.exports = class Footer extends Component {
static identity () {
return 'footer'
}
Copy link
Member

@goto-bus-stop goto-bus-stop Mar 7, 2018

Choose a reason for hiding this comment

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

the identity methods are no longer used, right? they are also defined in header and in info

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented Mar 12, 2018

Some more eyes on this would be great if people have time! cc/ @choojs/trainspotters

@yoshuawuyts yoshuawuyts changed the title [wip] choo components choo components Mar 12, 2018
@ungoldman
Copy link
Member

Not to derail but would this make more sense as a middleware rather than shipping with core?

@jondashkyle
Copy link

jondashkyle commented Mar 12, 2018

@ungoldman First-class support for components in the framework helps tremendously with the accessibility effort. Having both state and emit exposed without any prop juggling in userland being the most notable gain, personally. Introducing to core is consistent with Choo “the framework” (albeit a smol one.) :)

@yoshuawuyts
Copy link
Member Author

@ungoldman yep, what @jondashkyle says. Components have shown to be a requirement people have in almost every project. Being able to use them straight from core lowers the barrier, and allows us to assume people can build on top of it in every project.

Copy link
Member

@goto-bus-stop goto-bus-stop left a comment

Choose a reason for hiding this comment

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

this lgtm but i would also like signoff from someone who was more involved in designing it

@YerkoPalma
Copy link
Member

I'm ok with this, but I think docs should also be updated, to reflect the use of components.

@yoshuawuyts
Copy link
Member Author

ping @tornqvist @bcomnes @toddself your input on this patch would be greatly appreciated 🙏

// properties that are part of the API
this.router = nanorouter()
this.emitter = nanobus('choo.emit')
this.emit = this.emitter.emit.bind(this.emitter)
Copy link
Member

Choose a reason for hiding this comment

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

Removing this.emit breaks _prerender. Making sure that emit is a reference to the same function on every render (by referring a bound method on self) really helps with shallow diff of arguments. Also saves memory not having to allocate a new function on every 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.

Oopts, that was totally accidental. Great catch!

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed & added regression tests ✨

@yoshuawuyts yoshuawuyts force-pushed the choojs-components branch 2 times, most recently from bccc530 to c1f621d Compare March 13, 2018 13:33
if (!el) {
var args = []
for (var i = 0, len = arguments.length; i < len; i++) {
args.push(arguments[i])
Copy link
Member

Choose a reason for hiding this comment

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

We should probably drop Component and id from the args here (i.e. start iterating on 2). They are both prefixed on the next line anyway and by doing this we'd be offsetting the actual constructor arguments by an additional two.
This is what we're doing now:

class Foo extends Component {
  constructor (id, state, emit, the_class, id, actual_constructor_argument) {  }
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice, done!

@yoshuawuyts
Copy link
Member Author

Merged in @tornqvist's feedback. Thinking of merging this in 24 hours, and releasing it as a pre-release. Then follow up with a proper release next week. I think it's time to move this forward.

Please do chime in if there's any problems left with the implementation. If not, we'll be able able to try it out from a pre-release soon! 😁

assert.ok(this instanceof ChooComponentCache, 'ChooComponentCache should be created with `new`')

assert.equal(typeof state, 'object', 'ChooComponentCache: state should be type object')
assert.equal(typeof emit, 'function', 'ChooComponentCache: state should be type function')
Copy link

Choose a reason for hiding this comment

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

emit should be type function 🎹

Copy link
Member Author

Choose a reason for hiding this comment

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

thanks!

@yoshuawuyts yoshuawuyts merged commit bddcfbe into master Mar 30, 2018
@yoshuawuyts yoshuawuyts deleted the choojs-components branch March 30, 2018 16:19
@Flet
Copy link

Flet commented Mar 30, 2018

🎉 🎉 🎉 🎉 🎉

@yoshuawuyts
Copy link
Member Author

v6.11.0-preview1

tornqvist added a commit to tornqvist/choo that referenced this pull request Jun 21, 2018
…state

* upstream/master:
  6.12.1
  6.12.0
  typings: add app to app.use cb (choojs#665)
  update dependencies (choojs#663)
  ci: Node 7 → Node 10 (choojs#661)
  Update bel and yo-yoify references in docs to nanohtml. (choojs#660)
  Build for UMD (choojs#617)
  6.11.0
  Use nanoassert in the browser (choojs#651)
  Switch to nanohtml (choojs#644)
  v6.11.0-preview1
  choo components (choojs#639)
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.

10 participants