-
-
Notifications
You must be signed in to change notification settings - Fork 149
Adaptations for ReScript 10 / use records with optional fields #769
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work ! Thanks @cknitt.
I think we could improve styleObj being directly t so we don't even have to use styleObj function but beside this, it's perfect !
Updated PR for 10.0.0 release version. |
@cknitt can you check if everything I added is correct (especially for VirtualizedSectionList, not sure if that make sense to change as record...) ? Thanks :)
@cknitt can you check my latest commits please ? |
Looks good to me. For |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything is amazing, but I have concern for Style API changes.
src/apis/Style.res
Outdated
// Contains all of | ||
// - image style | ||
// - text style | ||
// - view style | ||
// - transform style | ||
// - shadow style | ||
// - layout style | ||
type styleObj = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a question here for everyday need:
Now we are supposed to do style={Style.styleObj({width: 10.->Style.dp})}
instead of style={Style.style(~width=10.->Style.dp,())}
. Is there really a direct benefit ? Because with style being styleObj, at the end, we don't save a single char :D
Could we imagine something shorter ? Or maybe directly a record ? I know that array would be an issue but... What if we only accept array as discussed in #632 ? This way, we could only type style={[{width: 10.->dp}]}
.
I have to admit that with themed app (light/dark mode) and predefined common styles, I have most of the time use array.
And it would be like React.useState() for example. Original api accepts value or function, but rescript bindings only accept the "most advanced" to avoid bloated api. By using array, we directly allow us to save chars everytime !
Any thoughts ? cc @Freddy03h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, no ~
anymore, no ()
at the end anymore that you can forget, more readable and more familiar to JS developers, definitely a benefit in any case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But it would certainly be nice to be able to avoid Style.style
/Style.styleObj
altogether.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how it could work in a type-safe manner though, given that nested style arrays are also allowed (and sometimes useful), and that we may also want to keep arrayOption
. I think we do need our abstract type (Style.t
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should just make it s
instead of styleObj
. Example:
let styles = {
open Style
StyleSheet.create({
"playButton": s({
display: #flex,
alignItems: #center,
justifyContent: #center,
borderWidth: StyleSheet.hairlineWidth,
}),
})
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will have to remove this then:
@module("react-native") @scope("StyleSheet")
external flatten: array<Style.t> => Style.t = "flatten"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's break all the things. It's been a while now that StyleSheet.create doesn't returns int anymore but directly styles. It's only validating some values & units.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
With all these breaking changes I guess we'll need a codemod?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MoOx I read that it could be back to int (or other value) in react-native-web with the new/next style system
Btw, I think I read somewhere that type record spread is coming, it this a thing ? |
Yeah, I pinged you in rescript-lang/rescript#5659. 😄 There is a PoC now: rescript-lang/rescript#5715 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess a codemode would be nice but I don't feel confortable handling it. Never did one and don't have much time right now.
But what if?...
We temporarily keep array, arrayOption & style functions (but deprecate them) and adjust their result... since RN handle nested array !?
- style() could return a array (here we use external + a tiny function ?)
- array/arrayOption could accepts array & return styles too ?
This could work and would avoid people a major breaking change ? Am I missing a thing ?
src/apis/Style.res
Outdated
switch style { | ||
| Some(style) => style | ||
| None => empty | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we use identity to do option => t ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because t
is a record type now, but None
is not a record.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I get that. I was just thinking that RN styles accepts undefined, null & falsy values...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah but the user may do
let x = Style.optional(None)
let color = x.color // 💥 runtime exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah right, without abstract type, that's mandatory :)
src/apis/StyleSheet.res
Outdated
@@ -7,5 +7,3 @@ external absoluteFillObject: Style.t = "absoluteFillObject" | |||
|
|||
@module("react-native") @scope("StyleSheet") | |||
external create: Js.t<'a> => Js.t<'a> = "create" | |||
@module("react-native") @scope("StyleSheet") | |||
external flatten: array<Style.t> => Style.t = "flatten" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if this can still work per RN docs. It's supposed to handle exactly this: flatten an array. Since we type styles != type t, this could still work right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I think you are right, I was confusing it with "%identity", this should still work as it is. So I can add it back.
But you won't be able to directly pass the result directly to a view's style prop anymore (as that expects an array now).
What we can do is have But external array: array<styles> => styles = "%identity"
external arrayOption: array<option<styles>> => styles = "%identity" is equivalent to external array: array<array<Style.t>> => array<Style.t> = "%identity"
external arrayOption: array<option<array<Style.t>>> => array<Style.t> = "%identity" which are not correctly typed. This was ok with an abstract type as a result, but is not correct anymore now. |
For array & arrayOption, we could turn them into a function instead of external ? |
Yes, but this has performance implications. |
The idea is still to have them deprecated. Do you think that's a bad idea to make them ? |
No, I can do that. 👍 |
BTW, I am wondering about the general performance implications of passing an array instead of a style object now. The style object would usually be created once (StyleSheet.create) and then always the same instance would be passed. When wrapping it in an array, this will be a new array instance every time. |
That's right. I never measured this. I use array everywhere but never thought about it. @Freddy03h are you doing the same, array inside jsx or do you compute them first ? I generally care about perfs when I "feel" that there is an issue, but having this everywhere could have an impact but I have no clue if that could be feel by the end user or not 😁 |
So this will run for every style unnecessarily passed within an array: We are really moving away from the zero cost idea here, I am getting second thoughts again. 😞 |
In practise for me this won't change a thing as I use array almost everywhere. |
I don't think it will be a performance issue. But… I'm thinking… array was just a convenient way of merging style prop, in a time spread syntax wasn't easily usable There is no difference between these in js : style={[style, styleFromProp, { paddingTop: insets.top }]}
style={{ ...style, ...styleFromProp, ...{ paddingTop: insets.top } }} So it could be possible to completely ditch the array! For now it's not seems to be possible with rescript record…
|
@Freddy03h using array or object is imo approximately the same result: on every render, you "change" styles. This don't work for dynamic styles as you always have to "get" the theme or dynamic base from somewhere in your app. In short: for people like you and me, approximately no diff. |
@MoOx It's also possible to open a PR on react-native to optimize flattenStyle for an array of 1 if we found perf issue But what are you thinking about ditching the array? |
@Freddy03h Actually ditching the array and just spreading would be nice, but the language support is not there yet. Also, you wrote:
If that's the case, then the style values won't be records and the spreading is not going to work. |
😅 … For the performance issue: to keep an usable app on low end device with Android 6, you need to memoize your components if there is too much rerenders. |
@MoOx @Freddy03h I have given this more thought over the weekend. There are various third party libs out there for rescript-react-native. If we change For me there are still too many uncertainties / moving parts here. Some concerns may be mitigated later though (when extensible records are available in ReScript so that components from third party libs can inherit their base props from components in rescript-react-native). Not so sure about others, like react-native-web maybe using ints for styles. For now, I would propose to finish this PR without the change to arrays for style props, i.e. still keeping Style.t abstract as it is now, and continue the discussions about arrays for style props in a separate issue. I would simplify things though so that there is a single type for style records (not viewStyleObj, textStyleObj etc.) and that it is used like I described above (with just let styles = {
open Style
StyleSheet.create({
"playButton": s({
display: #flex,
alignItems: #center,
justifyContent: #center,
borderWidth: StyleSheet.hairlineWidth,
}),
})
} And people can still use the existing style() function as an alternative. BTW, I was also thinking that maybe we should not deprecate the old creation functions yet, but wait for that until a later release to give users some time to transition. |
@MoOx Updated the PR as described. Can we get it merged and continue discussing/evaluating the array style props ideas elsewhere? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah looks good. You are right that this need some thoughts.
Closes #766.
Wait for ReScript 10 to be released before merging.
Trying to remain compatible as far as possible by keeping (but deprecating) existing creation functions (
@obj
).