Change startupjs
and all @startupjs/*
dependencies in your package.json
to ^0.43
.
No breaking changes
Added automatic caching for styles and creation of scoped models during react render.
This is considered to be an experimental feature. By default it's turned OFF
so nothing should break whatsoever.
To turn in ON
, pass observerCache: true
to the startupjs
preset in babel.config.js
:
['startupjs/babel.cjs', {
...,
observerCache: true
}]
To make sure caching is enabled, check the value of window.__startupjs__.DEBUG.cacheEnabled
in browser console.
Cache will be enabled for all components. You can explicitly prohibit a specific component from using cache by passing { cache: false }
to its observer()
:
export default observer(function Test ({ frequentlyChangedRandomColor }) {
return pug`
Div(style={ backgroundColor: frequentlyChangedRandomColor })
`
}, { cache: false })
After enabling caching you must carefully test your whole application because some components might have been relying on excessive renderings to function properly. So you might have to fix some things in your codebase to account for optimized rerenders.
Examples:
-
cache pure
style
. This will only work if you haveobserver
imported in the current file, this way we don't screw up the 3rd-party libraries which don't use startupjs.export default observer(function Test () { return pug` Div(style={ backgroundColor: 'red' }) ` })
-
cache pure
styleName
or any combination ofpart
,style
,*Style
,*StyleName
export default observer(function Test () { return pug` Div.div ` styl` .div background-color red ` })
-
cache scoped model created with
.at()
and.scope()
export default observer(function Games () { const [games, $games] = useQuery('games', { active: true }) return pug` each game in games Game($game=$games.at(game.id)) ` }) const Game = observer(({ $game }) => { const game = $game.get() return pug` Span= game.title ` })
The last example is especially important since writing code in this way simplifies code a lot in many places. Now you can (and should) pass models whenever possible to child components as arguments, instead of passing an id
and using useDoc
or useLocalDoc
.
Earlier in situations when you run useQuery
in the parent component and then render each item as a separate component the only way to do it easily and properly was to pass an item id and then do a useLocalDoc
. And you had to use useLocalDoc
, otherwise useDoc
will create an additional doc-only subscription and wait for it. Now this usecase is handled for you automatically, you just create a scoped model for the item inline using $items.at(item.id)
and pass it as $item
into the child component.
So this change alone will save you from making extra queries in many situations and will make the code easier to follow and more performant overall.