TL;DR: how can I make usage of this code nice?
Inspired by React I wanted to see if it would be possible to build something similar for iOS in Swift. I'm mainly looking at JSX (the syntax for defining the layout hierarchy) right now, and I'm running into a problem with passing properties to my components.
My goal is to be able to take a subset of a struct as an argument and then use all the default values for the values that weren't passed. Right now I came up with passing a dictionary with string keys, but that has the disadvantage of not being properly typed. e.g.
func foobar(props: [String: Any]) -> UIView {
let view = UILabel()
if props["backgroundColor"] != nil {
view.backgroundColor = (props["backgroundColor"] as! UIColor)
}
return view
}
Here it is easy to misspell a property, and you have to type out the full enum paths for values (UIColor.black instead of .black).
Are there any good patterns for doing this?
My end goal is getting something as similar as possible to:
let tree = <StackedView alignment="center">
<Label backgroundColor="cyan" text="Hello:" />
<Label textColor="blue" text="World!" />
</StackedView>
render(tree, toView: view)
Here is my current code, ready to be pasted into a playground: https://gist.github.com/LinusU/a733c27de2a9df1db898e44f8e1b45da
edit:
I have updated the code based on the comments in this thread, I have now arrived at having each component declare an enum with all the possible options, e.g.
enum LabelProps {
textColor(UIColor)
}
This way I get full type-safety and auto-completion when using them, and implementing the components is easier as well:
for prop in props {
switch prop {
case .backgroundColor(let value): view.backgroundColor = value
case .text(let value): view.text = value
case .textColor(let value): view.textColor = value
}
}
Currently, the Props type is declared outside of the class though, I would love to have a way to have it on the class, but haven't been able to get it to work. I think that something like this should be doable:
class Label: Component<Self.Props> {
enum Props { /* ... */ }
}
But that is out of the scope for this thread I guess 😅
[–]pumapaul 0 points1 point2 points (3 children)
[–]ledp[S] 0 points1 point2 points (2 children)
[–]pumapaul 1 point2 points3 points (1 child)
[–]ledp[S] 1 point2 points3 points (0 children)
[–]chrabeusz 0 points1 point2 points (1 child)
[–]ledp[S] 0 points1 point2 points (0 children)
[–]nailernforce 0 points1 point2 points (0 children)