The Composable Architecture — Apply into actual projects — Part 2: The raw skeleton of the Login screen

Duy Bui
Nerd For Tech
Published in
4 min readMay 9, 2021

--

Hello, welcome back to my The Composable Architecture tutorials series. As I said in the previous one, in this article, I will implement the Authentication phase, more specifically, it is the login screen. But wait, before getting into it, I would like to make sure that you do not miss any of my previous articles related to this framework— I believe they are extremely helpful for you.

Image credit: https://unsplash.com/photos/fGkBx7hX9Ms

To be really effective, I recommend rereading my previous post, especially the structure section to get an overview of what I’m going to do soon. And then, you will also easily grasp the knowledge that I am about to write in my little bit of time. Also, the purpose of this article is solely to set up a structure, so I am not going to make UI catchy or beautiful— (leave that interesting part for us). Ok, let’s get started.

Step 1: Define models

First, to keep the series’s content simple, the model here is just an object including email and password. There are two pieces of data that LoginView depends on. Of course, in the real world, the model must be more complicated.

Step 2: Create the view

Second, create the View — in this case, it's the Login View. So in this view, we need two text fields and one Login button.

// MARK: - Propertiers
@State private var email = ""
@State private var password = ""

// MARK: - View
var body: some View {
VStack() {
Text("Duy Bui - iOS Developer")
TextField("Email", text: self.$email)
TextField("Password", text: self.$password)
Button("Sign In") {}
}
}

Step 3: Define the Core

This is the most important part of this architecture, Core — so with the Login View, we are going to have the LoginCore. In this part, we will have 4 components:

  • LoginState struct
  • LoginAction enum
  • LoginEnvironment struct
  • loginReducer object

Let’s dive into the details

  • LoginState includes data that you think it's can be reflected by some actions in the LoginView. For example, after users fill in some texts in the email and password fields, we will definitely need to consider validating them to display the UI accordingly. So, I think I need one more property called `isFormValidated` besides `email` and `password` ones
public struct LoginState: Equatable {
public var email: String
public var password: String
public var isFormValidated: Bool {
return email.count > 0 && password.count > 0
}
}
  • LoginAction — this is the place where we will define actions happening in our View. Currently, I am thinking of 3 primary actions — change email and password text fields then tap on Login Button. In the future, if we have many more actions, we just need to add new cases in this action.
public enum LoginAction: Equatable {
case emailTextFieldChanged(text: String)
case passwordTextFieldChanged(text: String)
case loginButtonTap
}
  • LoginEnvironment — leave it empty. You can think this struct looks like the co-ordinator who will hold all dependencies like network or database mechanisms
public struct LoginEnvironment {
}
  • LoginClient — leave it empty as well — this class will handle the network call. It sends the body requests and gets the results back.
public struct LoginClient {
}

So, the LoginClient will have:

  • LoginRequest: includes parameters or headers, so on
  • LoginClient includes `live` and even `stub` versions for testing purpose

Step 4: Map ViewState with State

This ViewState will live inside the LoginView. It will handle the state of every single component on the view. The email and password fields are mapping from ViewState to State. This is quite straightforward and easy to understand.

Let’s move a higher step. The button color and its status depend on the `isFormValidated` parameter, so it will be mapped like this

Image credit: Duy Bui

So, that block of code looks like this

struct ViewState: Equatable {
var email: String
var password: String
var loginButtonColor: Color
var isLoginButtonDisabled: Bool
}

Conclusion

Let's see all the files in the Login folder which we have after this tutorial.

Ok, I think this article is long enough for setting up all things we need. In the next part, we are going to implement the logic for reducer part. I also connect all pieces together. Stay tuned. And don’t forget to share this article with your friends. Happy coding!

--

--