Navigating inside an Effect uses previous state

First off; Maybe even from the title I am already doing something wild but I at least want to see if this is possible or not. I have tried looking through examples and previous posts here but I can't find something that is exactly what I am trying to figure out.

I have a screen showing a list of Notes. Tapping one of them brings me to a screen displaying it's content. Bits of text etc. I am using UIKit.

My process is dispatching an action that stores a piece of state for the ViewController being presented to use, the Note that was clicked. Once that piece of state is set, I then return an Effect that goes to a Navigation reducer that will display the screen. I am currently experimenting with RxFlow as I like a Coordinator pattern for navigation and wanted to check this out, however, even hackily trying to present it without this approach does not work either.

It appears that when I am trying to display a screen from inside the TCA flow the store that is provided to the ViewController is the previous one. I can confirm that the state contains the right information after both the show and navigate actions are processed. However, I can hackily use DispatchQueue.main.async to avoid this, I want to know if there is something obvious I am missing? Or if this is a completely incorrect approach for something like this.

I would enjoy having the ability of navigating through the TCA flow, rather than always having to do something that goes back to the ViewController for it to then present the screen. I hope I have made sense, if there is something confusing please feel free to ask for clarity as it's quite late for me right now :sweat_smile:

@VinceMikhailKearney For a long time viewStore.publishers emitted at the same time as the view store's SwiftUI ObservableObject, which means if you try to access a view store's state in the publisher's sink it's still a tick behind (even though the value passed to the sink is the current value). This is due to how objectWillChange on ObservableObject emits right before the object actually changes. This behavior in TCA changed recently, though, to better accommodate UIKit apps. What version of TCA are you on?

Can you also provide some code as to how you observe state? An example of where viewStore.publisher is rendering old data would be helpful!

Hi @stephencelis! Thanks for the fast response!

Ah I see! Thanks for the explanation. I was wondering if this was the case but wasn't entirely sure where to look so I really appreciate this information! :blush:

I am currently using version 0.22.0, which I believe is the latest released 8 days ago? :blush:
I am using a Just(viewStore.note) approach so that I can set the data when the screen first appears, but then I don't want to the screen to update itself until a button is pressed to save the note. Something like:

func viewDidLoad() {
  super.viewDidLoad()
  Just(viewStore.note).sink { [weak self] note in
      guard let note = note, let self = self else { return }
      self.textView.text = note.text
  }
  // Other viewStore.publisher that are working exactly as intended
}

I understand the information you provided here, but I am wondering why this happens here when I am not using the publisher? :thinking: I confirmed that the state does in fact contain the right information, so I was surprised when creating the viewStore it doesn't hold that state, but rather than previous. If the action to update the state has completed and then returned an Effect that results in the navigation Coordinator presenting a screen I would have thought everything was updated/rendered on time for this? :blush:

Thanks,
Vince

Terms of Service

Privacy Policy

Cookie Policy