Question: pure rendering support
raveclassic opened this issue · comments
Hi!
First, thanks for this project, I was pleasantly surprised to know that css classnames concatination is already done after implementing it myself :) So I'll better go with this project.
I have a question about pure rendering optimization. As you always inject new theme
object to props pure rendering checking is no longer working using shallowEqual
.
There's of course a way to manually check both props without theme and only theme in shouldComponentUpdate
but that would be rather tedious to implement in each themed component.
On the other way I believe it's not responsibility of this library to check shouldComponentUpdate
.
So it's clear that to use both themr
and pure rendering one should write specific mixin/decorator.
I suggest to inject a Symbol to ThemedComponent
prototype and export it from the library. Then when decorating a themed component this symbol will indicate that pure decorator should also check props.theme
.
I understand that shouldComponentUpdate
could just relay on props.theme
existance but that would be too restrictive because I want to support a case when props.theme is set not in themr.
There's also another way to investigate - usage of Immutable.Map for the theme, then shallow equality check could just compare two theme objects.
What do you think?
Maybe there's an easier way?
Hi!! First of all thanks for your comment and sorry for this delayed response. I don't fully understand why theme
creates an issue for the shallow compare. If I'm getting it right, when you compare prevProps
and nextProps
it should return true
if you are passing the same theme. Generating a new object on each render is supposed to change the reference but if you compare the values you should get the same.
I'm not very familiar with this level of optimization though, but I understand that themr should be pure itself. I've tested this being what I understand is happening:
import shallowCompare from 'react-addons-shallow-compare'
const themeable = (style = {}, theme) => {
if (!theme) return style
return [ ...Object.keys(theme), ...Object.keys(style) ].reduce((result, key) => (
typeof theme[key] === 'string' && style[key] && theme[key].indexOf(style[key]) === -1
? { ...result, [key]: `${style[key]} ${theme[key]}` }
: { ...result, [key]: theme[key] || style[key] }
), {})
}
const getComposed = () => themeable(
{ foo: 'bar1234', baz: 'abc' },
{ foo: 'baz5678', bar: 'cde' }
)
console.log(shallowCompare(getComposed(), getComposed()))
// ---> true
If the theme changes you'd have to re-render because the className
are going to be different. Probably I'm missing something :/
You've got the point right - it's all about dynamic theme generation and passing it to the inner component which is also decorated with it's own theme. This way a merge always produces new object and its content should be shallowly compared together with the rest of props.
I'm writing a library of class decorators and currently in @Pure
decorator I'm making an assumption that if a theme
object is provided to props I'm excluding it from props for a separate shallow compare. That's ok and is working like a charm with the only thing that my decorator can be used in an environment without themr
and a theme
object passed to props. So I'd like to have some unique way to detect that a component has been already decorated by themr
and therefore I suggest using ES6 Symbols.
I'm sorry about plain text with no examples, I'm writing from mobile. If you don't mind I'll provide some examples tomorrow.
Have just reviewed your code - yes, you always create a new object anyway here and here. So there's always a new reference to theme
in props which makes shallowCompare
to always return true.
Here's the way that I check props now assuming that theme
object came from react-css-themr
. This was a Symbol marker which was injected here and then should be checked here before deprecation in favor of react-css-themr
.
I'd like to have a similar way to indicate that a component passed to @PURE
has been already decorated by @themr
.
I've rewritten my decorator to expliticly accept array of objects for separate shallow comparation, so this issue can be closed
Thanks @raveclassic !