Reswift: How to skip first state

Created on 13 Dec 2019  路  5Comments  路  Source: ReSwift/ReSwift

When subscriber start to subscribe a state, newState must be called.

I want to skip this first state.
Is there any way to do it?
I don't want to add property to judge first time or not.

Most helpful comment

Subscriptions are a forward-chain system. When you transform a subscription, the original subscription handles the transformation, and then forwards the observation call into the transformed subscription. If that has no further transformations, it then notifies the subscriber.

So a subscribe(self) { $0.select { $0.foo } } gets the following:
Original: Subscription<AppState>
Transformed Subscription<Foo>

Calling newValues on original executes the selection, and forwards to newValues on transformed, which then calls newState(...) on the subscriber.

It is a core behaviour for ReSwift to immediately notify subscribers. This matches standard redux behaviour.

If you wish to skip updates, you can use an instance variable and bail from the newState(...) call as you wish.

Alternatively, since observer is public, one could write an extension to Subscription to skip the first case by overriding the observer and discarding the call when oldState == nil. Please note the following code, while functional, has not been tested thoroughly and should be used at your own risk.

extension Subscription {
    public func skipFirst() -> Subscription<State> {
        return Subscription<State> { sink in
            self.observer = { oldState, newState in
                switch (oldState, newState) {
                case (.none, _):
                    return
                default:
                    sink(oldState, newState)
                }
            }
        }
    }
}

// Then:
store.subscribe(self) { $0.skipFirst() }

I do, however, also wonder about the requirements that need to be able to skip that first notification. It feels to me very anti-redux to need to do that, and the actual functionality may be better off implemented some other way (eg, in middleware)

All 5 comments

Some people use reactive extensions that may allow you to do this, but I don鈥檛 know the status of those regarding the current ReSwift as I don鈥檛 use them myself.

What are you trying you accomplish? Don鈥檛 you need to initialize the view鈥檚 state somehow? If you鈥檙e performing a side effect within the subscription, use a middleware instead.

@danielmartinprieto
Thank you for reply!

What are you trying you accomplish? Don鈥檛 you need to initialize the view鈥檚 state somehow?

I don't need to initialize. I want to receive notification, only when state is changed.

I think below code throw newState with originalSubscription.

```Store.swift
fileprivate func _subscribe(
_ subscriber: S, originalSubscription: Subscription,
transformedSubscription: Subscription?)
where S.StoreSubscriberStateType == SelectedState
{
let subscriptionBox = self.subscriptionBox(
originalSubscription: originalSubscription,
transformedSubscription: transformedSubscription,
subscriber: subscriber
)

    subscriptions.update(with: subscriptionBox)

    if let state = self.state {
        originalSubscription.newValues(oldState: nil, newState: state)
    }
}

```

Do you know it must be originalSubscription ?

if transformedSubscription is used, I can handle first state with Subscription.

I'm still not sure what you want to accomplish here but checking the code you just posted I don't understand either why does it call the original and not the transformed subscription. Also, I don't know why the "subscription box" needs the original subscription if it has been transformed.

@DivineDominion @mjarvis do you guys know the answer to these questions?

Subscriptions are a forward-chain system. When you transform a subscription, the original subscription handles the transformation, and then forwards the observation call into the transformed subscription. If that has no further transformations, it then notifies the subscriber.

So a subscribe(self) { $0.select { $0.foo } } gets the following:
Original: Subscription<AppState>
Transformed Subscription<Foo>

Calling newValues on original executes the selection, and forwards to newValues on transformed, which then calls newState(...) on the subscriber.

It is a core behaviour for ReSwift to immediately notify subscribers. This matches standard redux behaviour.

If you wish to skip updates, you can use an instance variable and bail from the newState(...) call as you wish.

Alternatively, since observer is public, one could write an extension to Subscription to skip the first case by overriding the observer and discarding the call when oldState == nil. Please note the following code, while functional, has not been tested thoroughly and should be used at your own risk.

extension Subscription {
    public func skipFirst() -> Subscription<State> {
        return Subscription<State> { sink in
            self.observer = { oldState, newState in
                switch (oldState, newState) {
                case (.none, _):
                    return
                default:
                    sink(oldState, newState)
                }
            }
        }
    }
}

// Then:
store.subscribe(self) { $0.skipFirst() }

I do, however, also wonder about the requirements that need to be able to skip that first notification. It feels to me very anti-redux to need to do that, and the actual functionality may be better off implemented some other way (eg, in middleware)

@danielmartinprieto @mjarvis
Thank you so much for your hospitality!!

I鈥檓 sorry about i can鈥檛 explain what i want to do concretely..

It is a core behaviour for ReSwift to immediately notify subscribers. This matches standard redux behaviour.

It feels to me very anti-redux to need to do that, and the actual functionality may be better off implemented some other way (eg, in middleware)

I realized that what I want to do was strange. I will consider whether it can be realized by other way.
Thank you for sample code. If I use that, it is in my own risk.

I close this issue. Thank you so much.

Was this page helpful?
0 / 5 - 0 ratings