Skip to content
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

[ Question ] How to use path variable in child view #1

Closed
iRiziya opened this issue Aug 12, 2022 · 13 comments
Closed

[ Question ] How to use path variable in child view #1

iRiziya opened this issue Aug 12, 2022 · 13 comments
Labels
question Further information is requested

Comments

@iRiziya
Copy link

iRiziya commented Aug 12, 2022

I am following the given example but it is still unclear that how can I use the same path variable in child view. The main path variable should be accessible to all its child view and must be binded.

I have LoginView and ForgetPasswordView. I have declared path as below in LoginView

@State var path = PathPresenter.Path()

and embedded login layout inside PathPresenter like this

PathPresenter.RoutingView(path: $path){ 
     VStack{
          //Login layout
     }
 }

and then I am appending ForgetPasswordView in this path

path.append(ForgetPasswordView(),
                       type: .animated(transition: .move(edge: .leading), animation: .easeIn))

but now the back button is inside the ForgetPasswordView so I am wondering how can I use the same path variable to go back or to append any new View?

@alexdremov
Copy link
Owner

alexdremov commented Aug 12, 2022

Hello!

You can pass a path binding to ForgetPasswordView by defining
@Binding var path: PathPresenter.Path in ForgetPasswordView.

Then, you can pass path during initialisation of ForgetPasswordView:


path.append(ForgetPasswordView(path: $path),
                       type: .animated(transition: .move(edge: .leading), animation: .easeIn))

Now you can use path in ForgetPasswordView as usual

@alexdremov
Copy link
Owner

Also, architecture-wise, I would suggest not to pass path all around the app.

It may be fine in small examples like yours, but on a large scale, if views will push and pop uncontrollably, it will be a mess

@alexdremov alexdremov changed the title how to use path variable in child view [ Question ] How to use path variable in child view Aug 12, 2022
@alexdremov alexdremov added the question Further information is requested label Aug 12, 2022
@iRiziya
Copy link
Author

iRiziya commented Aug 12, 2022

Thanks for the quick response. @Alexroar

I already tried @Binding but its not working as expected. And also my app is large so what would be best approach in that case?

@iRiziya
Copy link
Author

iRiziya commented Aug 12, 2022

Alright @Binding worked this time because I removed the embedded PathPresenter from ForgetPasswordView. But I am worrying about infinite navigation chain If I will have to navigate through so many screens.

@alexdremov
Copy link
Owner

I already tried @binding but its not working as expected. And also my app is large so what would be best approach in that case?

Complete working example:

import SwiftUI
import PathPresenter

struct ContentView: View {
  @State var path = PathPresenter.Path()
  var body: some View {
    PathPresenter.RoutingView(path: $path){
       VStack {
         Spacer()
         Button("Forgot password") {
           path.append(
            ForgotPasswordView(path: $path),
            type: .animated(
              transition: .scale,
              animation: .easeIn)
           )
         }
         Spacer()
       }
       .frame(maxWidth: .infinity, maxHeight: .infinity)
     }
    .border(.blue)
  }
}

struct ForgotPasswordView: View {
  @Binding var path: PathPresenter.Path

  var body: some View {
    VStack(alignment: .center){
      Spacer()
      VStack {
        Text("Restore password screen")
        Button("back") {
          path.removeLast()
        }
      }
      .background(.white)
      Spacer()
    }
    .frame(maxWidth: .infinity, maxHeight: .infinity)
  }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

@alexdremov
Copy link
Owner

alexdremov commented Aug 12, 2022

Alright @Binding worked this time because I removed the embedded PathPresenter from ForgetPasswordView. But I am worrying about infinite navigation chain If I will have to navigate through so many screens.

You need to somehow restrict subviews to be able to do limited actions with path. In your example you do not need to pass the whole path to the subview. You can pass some closure like backAction: () -> () that will be called when user presses back button.

And inside this closure you will do needed actions with path.

Also, check out MVVM-C architecture. I believe it's a nice extension of MVVM that has good control over navigation.

@alexdremov
Copy link
Owner

Also, I'm planning to extend this library with wrapper around path that will restrict views from doing some mess with all other views ;)

@iRiziya
Copy link
Author

iRiziya commented Aug 12, 2022

Alright got it. Thanks.

@iRiziya
Copy link
Author

iRiziya commented Aug 12, 2022

Can you make it global? so we can use it on every page as an EnvironmentObject.

I am using a similar library for SwiftUI navigation but its not working for macOS because of missing NavigationView

@alexdremov
Copy link
Owner

Can you make it global? so we can use it on every page as an EnvironmentObject.

You can make a class wrapper and pass it as EnvironmentObject

class PathObserved: ObservableObject {
    @Published var path = PathPresenter.Path()
}

But if you need this object in global space, it's a smell of bad code architecture. This library was specifically designed without EnvironmentObjects and ObservableObject.

@iRiziya
Copy link
Author

iRiziya commented Aug 12, 2022

Ah ok. It's hard to deal with Navigation in macOS so I'll have to go for any of this. Can the given class wrapper create a mess for large app having many pages?

@alexdremov
Copy link
Owner

alexdremov commented Aug 12, 2022

Can the given class wrapper create a mess for large app having many pages?

The biggest concern I have is such situation:

  • View A starts operating and pushed to stack
  • View B starts operating and pushed to stack
  • View A stops operating and removes last view from stack, supposing that it removes itself, but actually it removes view B

Result: view B removed unexpectedly, and view A is not not removed. So, yes. Uncontrollable pushing/popping of views will hurt your app.

I will try to address such issue in future releases, creating new structure for managing such situations.

@iRiziya
Copy link
Author

iRiziya commented Aug 13, 2022

Ok thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants