> ## Content Index
> Fetch the complete content index at: https://mindsers.blog/llms.txt
> Use this file to discover other available public pages before exploring further.

# Optimize your SwiftUI code: Two ways to avoid duplication
- URL: https://mindsers.blog/en/post/optimize-your-swiftui-code-two-ways-to-avoid-duplication/
- Published: 2023-06-24T14:19:20.000Z
- Updated: 2023-09-10T18:43:12.000Z
- Author: Nathanaël Cherrier
- Tags: coding-tech, swift, best practices, cleancode, #lang-en

**Code duplication** is a real problem in applications. Having a lot of **duplicate code** means “complicated maintenance” but also a catastrophic experience.

I have two methods to avoid this problem in my [Swift applications](https://mindsers.blog/topic/swift/). I'll tell you all about them in this article.

## Custom components for greater SwiftUI code modularity

As you would with other frameworks, SwiftUI allows you to create views in a declarative/descriptive way.

The views are composed of other views and the pattern can be repeated endlessly on several levels.

```swift
struct SignInScreen: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Text("Connect")
            Spacer()
        }
    }
}

```

In the example above, the `SignInScreen` view is composed of a `VStack` view, a `Text` view and a `Spacer` view. Same operation therefore as a web framework or the global component will be composed of several smaller components.

Since views are just assemblies of views, we too can create our own views to bring together repeating elements.

```swift
struct SignInScreen: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            TextField("Email address", text: $email)

			DividerCustom()
            
            Button("Connect") {
                // action
            }
        }
    }
}

struct SignUpScreen: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            TextField("Email address", text: $email)

			DividerCustom()
            
            Button("Sign Up") {
                // action
            }
        }
    }
}

struct DividerCustom: View {
    var body: some View {
        HStack(alignment: .center) {
            VStack {
                Divider()
                    .frame(height: 1.0)
                    .background(.green)
            }
            Text("ou")
            VStack {
                Divider()
                    .frame(height: 1.0)
                    .background(.green)
            }
        }
    }
}

```

The `DividerCustom` view combines three other views and thus forms a view that is called in the `SignInScreen` and `SignUpScreen` view.

Modifying the `DividerCustom` code will update the element in both components where it is used. This **prevents the code from being duplicated** several times in the application.

## Optimization with modifiers and ViewModifier

Sometimes, what is duplicated is not a set of components but a set of modifications on a single view.

```swift
struct Buttons: View {
    var body: some View {
        Button {
            // action
        } label: {
            Label("Connect with Google", image: "GoogleLogo")
                .frame(maxWidth: .infinity)
        }
        .padding()
        .frame(minWidth: 300, alignment: .center)
        .background(backgroundColor)
        .foregroundColor(foregroundColor)
        .cornerRadius(30)
        .font(.Theme.regular(size: 16))

        Button {
            // action
        } label: {
            Label("Connect with Facebook", image: "FacebookLogo")
                .frame(maxWidth: .infinity)
        }
        .padding()
        .frame(minWidth: 300, alignment: .center)
        .background(backgroundColor)
        .foregroundColor(foregroundColor)
        .cornerRadius(30)
        .font(.Theme.regular(size: 16))

        Button {
            // action
        } label: {
            Label("Connect with GitHub", image: "GitHubLogo")
                .frame(maxWidth: .infinity)
        }
        .padding()
        .frame(minWidth: 300, alignment: .center)
        .background(backgroundColor)
        .foregroundColor(foregroundColor)
        .cornerRadius(30)
        .font(.Theme.regular(size: 16))
    }
}

```

In the example above, we want to display three login buttons for different services.

We don't want to change the behavior of a classic button or even associate it with other views so that they work together. What we want here is to modify the design of the button so that all the buttons look the same.

We will end up with 6 lines of modifications of a button which are duplicated each time a new button is created.

If I ultimately want to change the button's maximum width, I'll have to apply the change manually for each button!

One solution to **avoid code duplication** (and **simplify application maintenance**) in this situation is `ViewModifiers`. This is a very simple way to apply modifiers to multiple views:

```swift
struct BasicButton: ViewModifier {
    let backgroundColor: Color
    let foregroundColor: Color
    
    func body(content: Content) -> some View {
        content
            .padding()
            .frame(minWidth: 300, alignment: .center)
            .background(backgroundColor)
            .foregroundColor(foregroundColor)
            .cornerRadius(30)
            .font(.Theme.regular(size: 16))
    }
}

```

A `ViewModifier` is a `struct` with a `body` function. It is this function that will apply the styles to our views.

To use it we use the generic modifier `modifier()` as follows:

```swift
Button {
  // action
} label: {
  Label("Connexion avec GitHub", image: "GitHubLogo")
    .frame(maxWidth: .infinity)
}
.modifier(BasicButton(backgroundColor: .black, foregroundColor: .white))

```

And that's it!

`BasicButton` will apply the styles to our `Button` view with no more effort.

To make the code a little more elegant, here is a little trick:

1. We first add a function to the `View` class that will call the modifier.  
Note also the use of optional parameters so you don't have to mention them if they do not change.
2. And we call this function from our Button view like classic modifiers

You can also limit the use of this modifier to the `Button` view by extending the `Button` class rather than `View`, as we have done here.

The downside is that you will only be able to call the modifier directly on the view. It cannot be chained after other modifiers, because this one return an object of type `View` and not `Button`.

## Conclusion

As already discussed, **avoiding code duplication** is not only a good practice to make your code look "pretty". Rather, it's one of the easiest ways to **optimize your code** to **reduce development time** and **application maintenance time**.

Do not hesitate to use the `ViewModifier` or the creation of custom components to optimize your SwiftUI code.