-
-
Notifications
You must be signed in to change notification settings - Fork 399
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
Dynamic Sheets for theming and animations #356
Comments
So when sheets are updated rules will change but the class names remain the same right? |
Yes, we need to keep class names static, because we have no way to update the class name on an element from jss stand point. |
Updated the description. |
Ok, I see that the end goal is to have an internal solution for I just finished to pulish a fix for the PR that allows a ThemeProvider in React to inject a theme descriptor (meaning an object that defines variables) to provide those variables to all decorated Components using the current theme. Definitely my approach will fulfill theming only for react users. |
Just mentioning here that your approach for the ThemeProvider will break, because pure components (i.e. ones that return |
@mxstbr I understand the fact that pure components won't update if context changes. But the components that consume the Anyway thanks for flagging that out, I would add some more unit tests to verify. |
No, pure components block context updates. If a component returns Imagine a class NeverRerender extends Component {
// Never rerender this component after the first render
shouldComponentUpdate() { return false; }
render() { return this.props.children; }
} Now if you have a component tree like this: <ThemeProvider theme={someTheme}>
<NeverRerender>
<ThemedButton />
</NeverRerender>
</ThemeProvider> The This is why you need a (See this very old issue for a huge discussion about this: facebook/react#2517) |
Please refocus on the proposed idea, which is a solution independent of react. |
Gotcha now. Indeed a solution independent of react is ideal. Thanks again for the clarification |
What about streams? const sheet = jss.createStyleSheet()
const ruleStream = propsStream
// compose rule
.map(({buttonColor, padding, color}) => ({
button1: {
padding: 15,
color: buttonColor,
},
button2: {
color,
padding,
}
}))
// check if changed
.distinctUntilChanged()
const sheetStream = Observable.of(jss.createStyleSheet())
// combine sheet with rules
.combineLatest(ruleStream, (sheet, rules) => sheet.setRules(rules))
// attach on every change
.do((sheet) => sheet.attach())
.finally(() => sheet.detach()) Also something related https://github.com/davidkpiano/RxCSS |
Streams seems to be out of scope for this issue, it can be a separate library. This issue is about a lower level implementation I think. I would be more than happy if someone does a streaming abstraction on top of jss though. |
I am concerned about whether the keyword |
I think if you use it with react, you will really pass the props, similar to styled-components. |
It wasn't clear for me on the proposal, so props can be updated on a per style sheet level. 👍 |
I thought about this more. Because the class names remain static as you said, this wouldn't work for React. Normally we share a StyleSheet among the same components, changing the StyleSheet according to one's individual props will change the appearance of all other components of the same kind. Styled-Components creates new class names for each change, that can be reused among the same components. We would need to have a similar approach. Maybe having a class name for the static part and a class name for the dynamic one, that varies. |
We definitely need to append new variations of rules. We shouldn't be replacing existing since as you rightly mentioned, it will change the look/feel for all instances. |
@cvle looking into it again: yeah, dynamic rules can't share class names between elements. |
Here is an update on the progress:
|
Right now plugins do not react on dynamic values changes, this will be part of a separate feature, probably a new hook |
Probably we should not retry styled-components mistakes. Instead of this we can keep rendering architecture consistent with React.js (+ React Native) by introducing Virtual CSS to JSS. It also could include a kind of Reconciliation algorithms and ReactDOMServer. It means on each That is a part of the one of our React Native applications which we developed for our customer a few months ago: // ...
render() {
// ...
const fontSize = props.fixedFontSize ? INSIGHTS_FONT_SIZE : scaledFontSize || basicFontSize
const insightTextStyle = [
styles.itemText,
{ fontSize },
isScaling && styles.itemTextScaling,
]
const containerStyles = [
styles.item,
props.style,
isScaling && styles.itemScaling,
]
return (
<TouchableOpacity
activeOpacity={0.75}
style={containerStyles}
onPress={this._onCardPress}
>
{isScaling && (
<View style={[styles.itemInnerScaling]}>
<AutoText
style={styles.itemText}
maxHeight={maxContentHeight}
initialFontSize={scaledFontSize || BASIC_FONT_SIZE}
onComplete={({ fontSize }) => this.handleScaleComplete({ fontSize })}
>
{finalContent}
</AutoText>
</View>
)}
// ... As you noticed - React Native uses Inline Styles approach because it's a JS-to-Native-Controls bridge. For React Web we can use just something like: render() {
const myCardStyle = stylesheet.renderToDOM([
styles.myCard,
styles.cardWithToolbar,
])
return (
<MyCard className={myCardStyle} />
)
} Or: render() {
const myCardStyle = JSSForDOM.render(this, [
styles.myCard,
styles.cardWithToolbar,
])
return (
<MyCard className={myCardStyle} />
)
} But there is only one problem - See also: |
Merged. |
released |
The idea is to have value functions and rule functions which accept an object and let JSS render them dynamically. This will allow us efficient dynamic theming. The idea has been around for a while, but this time me and @nathanmarks have got a plan.
What signature will value function and rule function have?
How do we know if a rule or prop needs a rerender?
We don't, we just call all dynamic values and compare new results with the current once.
We need to have a proof that calling all dynamic values on each update is an actual perf problem. Right now this is a premature optimization, but if we need it, here are some options:
All suggestions are NOT exclusive.
Suggestion 1
Caching is ensured by the user. It is an opt-in.
Suggestion 2
It is basically suggestion 1 + a helper function which allows nicer caching notation.
Suggestion 3
Its a caching integrated into JSS itself.
How do we make sure to render minimum CSS?
Fallbacks
We need to make sure fallbacks are rendered first, like we already do (@mxstbr pointed this out).
Example
We will need a registry for dynamic rules and values.
When to modify rules and when to copy.
API for passing sheet props.
We need an API which can be called with an object as param, so that JSS can call dynamic values/rules and take care of the rendering.
Example
How to know what to render when new props is passed
We will try to rerender all dynamic values/rules. Caching mechanism will prevent performance issues.
What are the valid edge cases for perf?
The text was updated successfully, but these errors were encountered: