javivelasco / react-css-themr

Easy theming and composition for CSS Modules.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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