| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Please go to this Server-Driven-UI Architecture using UIComponents if you would like to read it on Medium platform
This article will talk about
Consider an entertainment app like Hotstar, whose contract is defined as shown below. On the left are the components from the server(ServerComponent), and on the right are the corresponding UI Components.
For every ServerComponent, we have a corresponding UIComponent.
Swift is a UI toolkit that lets you design application screens in a programmatic, declarative way.
struct NotificationView: View {
let notificationMessage: String
var body: some View {
Text(notificationMessage)
}
}This is a three-step process.
Input: Firstly, for the UIComponent to render itself, it should be provided with data.
Output: UIComponent defines its UI. When used for rendering inside a screen, it renders itself based on the data (input) provided to it.
protocol UIComponent {
var uniqueId: String { get }
func render() -> AnyView
}Let's look at NotificationComponent.
struct NotificationComponent: UIComponent {
var uniqueId: String
// The data required for rendering is passed as a dependency
let uiModel: NotificationUIModel
// Defines the View for the Component
func render() -> AnyView {
NotificationView(uiModel: uiModel).toAny()
}
}
// Contains the properties required for rendering the Notification View
struct NotificationUIModel {
let header: String
let message: String
let actionText: String
}
// Notification view takes the NotificationUIModel as a dependency
struct NotificationView: View {
let uiModel: NotificationUIModel
var body: some View {
VStack {
Text(uiModel.header)
Text(uiModel.message)
Button(action: {}) {
Text(uiModel.actionText)
}
}
}
} class HomePageController: ObservableObject {
let repository: Repository
@Published var uiComponents: [UIComponent] = []
..
..
func loadPage() {
val response = repository.getHomePageResult()
response.forEach { serverComponent in
let uiComponent = parseToUIComponent(serverComponent)
uiComponents.append(uiComponent)
}
}
}
func parseToUIComponent(serverComponent: ServerComponent) -> UIComponent {
var uiComponent: UIComponent
if serverComponent.type == "NotificationComponent" {
uiComponent = NotificationComponent(serverComponent.data, serverComponent.id)
}
else if serverComponent.type == "GenreListComponent" {
uiComponent = GenreListComponent(serverComponent.data, serverComponent.id)
}
...
...
return uiComponent
}This the last part. The screen’s only responsibility is to render the UIComponents.
struct HomePageView: View {
@ObservedObject var controller: HomePageViewModel
var body: some View {
ScrollView(.vertical) {
VStack {
ForEach(controller.uiComponents, id: \.uniqueId) { uiComponent in
uiComponent.render()
}
}
}
.onAppear(perform: {
self.controller.loadPage()
})
}
}All the UIComponents are rendered vertically using a VStack inside. As the UIComponents are uniquely identifiable, we can use the ForEach construct for rendering.
Since all the components conforming to UIComponent protocol must return a common type, the render() function returns AnyView. Below is an extension on the View for converting it toAnyView.
extension View {
func toAny() -> AnyView {
return AnyView(self)
}
}We saw how UIComponent can be used to give the server control over the UI of the application. But with UIComponents you can achieve something more.
Let’s consider a case without server-driven UI. It's often the case that the pieces of UI are used many times across the application. This leads to duplication of the view and view logic. So, it’s better to divide the UI into meaningful, reusable UI-components.
Having them this way will let the domain-layer/business layer define and construct the UI components. Additionally, the business-layer can take the responsibility of controlling the UI.
Have a look at the article Android Jetpack Compose — Create a Component-Based Architecture, which explains UI-Components in detail. As it uses Jetpack compose-Android’s declarative UI kit, it wouldn’t be hard to understand.
| Back | FazBrowse Home | New Git URL |