-
Notifications
You must be signed in to change notification settings - Fork 24.5k
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
Platform.select method #7220
Platform.select method #7220
Conversation
obj && typeof obj === 'object', | ||
'Platform.select: Must be called with an object' | ||
); | ||
invariant( |
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.
Think we don't want this because you should be able to run code like this:
Platform.select({
android: { ... }
})
and have the Android style get filtered out on iOS even if there are no iOS-specific styles.
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.
That's true, however the good thing is it can be used with non-style values and also at any level of StyleSheet object.
That means it's tricky to return a default value when Platform key is missing, like in the below example:
// will throw on Android, we can return an `{}` as a default, but then, the next example wont' work
Stylesheet.create({
...Platform.select({
ios: {}
})
})
and
// here it might work, but it might be unexpected
StyleSheet.create({
container: {
marginTop: Platform.select({
ios: 5,
})
}
})
and forgot to specify another platform.
My initial reasoning was that this is intended to be used when you have values for both
platforms to support - otherwise you can just supply an empty object.
PS. I have just noticed that it's going to also throw when value is falsy (e.g. 0
given for marginTop, so that will have to be handled as well)
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.
Agreed with @ide, I would remove that invariant. Not specifying an android block if you are on ios is okay.
By analyzing the blame information on this pull request, we identified @emilioicai and @knowbody to be potential reviewers. |
var Platform = { | ||
OS: 'ios', | ||
select: (obj: Object) => { | ||
invariant( |
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.
Remove this one as well. This is going to be a hot path and the error isn't very useful.
This is going to be the most useful dummy one liner I've seen in a while :) |
Can you write jest tests too? |
@ide sure, doing that now. Shall I also add a simple test for |
render() { | ||
return Platform.select({ | ||
ios: <ViewIOS />, | ||
android: <ViewAndroid />, |
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.
This is probably not going to work as you would expect. You're going to require the Android component on iOS and it may very well throw in this environment.
You'll likely want to write this as
var Component = Platform.select({
ios: () => require('ComponentIOS'),
android: () => require('ComponentAndroid'),
})();
return <Component />;
It cannot hurt :) |
I'm happy with the diff. Any other input @ide? |
returns the value for the platform you are currently running on. | ||
|
||
```javascript | ||
var { Platform } = React; |
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.
actually, remove this, you're not doing the same for StyleSheet
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.
Would you mind clarifying? (Is the PR update allowed when shipping in progress?)
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 remove this line, we would assume that people know how to require Platform.
For a shipping in progress, it'll only be picked up if I re-shipit.
We can just leave it for now, or kill it in another commit once it lands
🚢 🇮🇹 |
@facebook-github-bot shipit |
Could you update the pull request description with the two examples that you added in the doc. I want to tweet about this and it'll make for a better landing page :) |
Thanks for importing. If you are an FB employee go to Phabricator to review. |
All righty. Should be done now. |
Does anyone have a good plan for dead code eliminating the unused platform? |
@sebmarkbage May be someone could write a babel plugin transform this code at build time instead of runtime, so that Platform.select({
ios: {
backgroundColor: 'red',
},
android: {
backgroundColor: 'blue',
},
}), becomes {
backgroundColor: 'red',
}, |
@satya164 here you go https://astexplorer.net/#/o5XwSweFRa |
Awesome @thejameskyle :D cc @skevy should we include in our preset? |
Hello, This feature seems great. Though I'm wondering why the way platform specific css rules is defined in the F8 app was not preferred :
In F8StyleSheet.js :
From a user's perspective it would seem like there is less boilerplate code to write compared to using Platform.select and a spread operator. Do you think it's worth creating a pull request for this ? |
Thank you @Bhullnatik :) |
The gist of it is that we are trying to have decoupled concepts as much as possible. We don't want to tie in platform specific behavior with stylesheets. Chosing different things to do based on the platform is not limited to stylesheets and we'd rather have a specific api for it. Now, we also need to make sure that developer experience is taken into account and verbosity is an important piece of it |
Also this is something that is easy to do in user space without changes to the RN core so if you like F8StyleSheet's pattern, you should reimplement it and publish it to npm instead of sending PRs. |
so I created this: https://github.com/knowbody/react-native-platform-stylesheet and published to npm so you can just: |
Summary: Kudos to frantic for this amazing idea! Works really well (yet so simple!) Basically we had a discussion with vjeux and frantic and others in the PR facebook#7033 how to handle platform-specific stylesheets in a similar to F8 app way. There were quite a few nice ideas there, however that one seems to be the smallest yet the most powerful. Basically there's a `Platform.select` method that given an object, will select a `obj[Platform.OS]` value. It works with styles: `Platform.select({ ios: {}, android: {} })` with messages: `<Text>{Platform.select({ ios: 'Check the App Store', android: 'Check Google Play' })}</Text>` and also works well with components (similar to Wallmart idea of <PlatformSwitch />) - relevant example included in diff. Closes facebook#7220 Differential Revision: D3221709 Pulled By: vjeux fb-gh-sync-id: 0a50071f2dcf2273198bc6e2c36e19bca97d7be9 fbshipit-source-id: 0a50071f2dcf2273198bc6e2c36e19bca97d7be9
Summary: Kudos to frantic for this amazing idea! Works really well (yet so simple!) Basically we had a discussion with vjeux and frantic and others in the PR facebook#7033 how to handle platform-specific stylesheets in a similar to F8 app way. There were quite a few nice ideas there, however that one seems to be the smallest yet the most powerful. Basically there's a `Platform.select` method that given an object, will select a `obj[Platform.OS]` value. It works with styles: `Platform.select({ ios: {}, android: {} })` with messages: `<Text>{Platform.select({ ios: 'Check the App Store', android: 'Check Google Play' })}</Text>` and also works well with components (similar to Wallmart idea of <PlatformSwitch />) - relevant example included in diff. Closes facebook#7220 Differential Revision: D3221709 Pulled By: vjeux fb-gh-sync-id: 0a50071f2dcf2273198bc6e2c36e19bca97d7be9 fbshipit-source-id: 0a50071f2dcf2273198bc6e2c36e19bca97d7be9
Summary: Kudos to frantic for this amazing idea! Works really well (yet so simple!) Basically we had a discussion with vjeux and frantic and others in the PR facebook#7033 how to handle platform-specific stylesheets in a similar to F8 app way. There were quite a few nice ideas there, however that one seems to be the smallest yet the most powerful. Basically there's a `Platform.select` method that given an object, will select a `obj[Platform.OS]` value. It works with styles: `Platform.select({ ios: {}, android: {} })` with messages: `<Text>{Platform.select({ ios: 'Check the App Store', android: 'Check Google Play' })}</Text>` and also works well with components (similar to Wallmart idea of <PlatformSwitch />) - relevant example included in diff. Closes facebook#7220 Differential Revision: D3221709 Pulled By: vjeux fb-gh-sync-id: 0a50071f2dcf2273198bc6e2c36e19bca97d7be9 fbshipit-source-id: 0a50071f2dcf2273198bc6e2c36e19bca97d7be9
Platform.select, given an object containing Platform.OS as keys, returns the value for the platform you are currently running on.
It works with styles:
as well as with functions:
The entire implementation :)
var Platform = { OS: 'ios', + select: (obj: Object) => obj.ios, };
Kudos to @frantic for this amazing idea suggested in #7033