Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DivineDominion/ff78a36a08d4b83aa480cc7e2e18a1c3 to your computer and use it in GitHub Desktop.
Save DivineDominion/ff78a36a08d4b83aa480cc7e2e18a1c3 to your computer and use it in GitHub Desktop.
Zettel note about ReSwift reducer partitioning

Title: Focus ReSwift reducers to one state change ID: 201801041611 Tags: #reswift #srp

ReSwift reducers should not have conditional side-effects, changing different states out of convenience. That makes it hard to notice which action changed what. The condition is most of the problem, I think.

An ideal approach would be to have 1 reducer/action pair for each substate change.

When reducers overlap (they touch the same state), this can become a problem. (IncreaseCounter and DecreaseCounter are a bad example.) Conditional changes to another substate should be extracted as another action which is dispatched by a Middleware under similar circumstances.

Bad example with 1 reducer doing 2 things:

public func reduceReloadingResults(
    _ action: ReloadingResults, 
    state: AppState) -> AppState 
{
    var state = state

    state.search.reloadCurrentSearch()

    if reloadingDisplayedNoteIsNecessary() {
        // Overlaps with `DisplayingNote` action:
        state.display = DisplayState(...)
    }

    return state
}

Better example with a middleware dispatching an already established action:

public func reduceReloadingResults(
    _ action: ReloadingResults, 
    state: AppState) -> AppState 
{
    var state = state
    state.search.reloadCurrentSearch()
    return state
}

let refreshDisplayedNoteWhenItTriggeredReloadMiddleware:
    Middleware<AppState> = { dispatch, getState in
    return { next in
        return { action in
            guard let reloadAction = action as? ReloadingResults,
                // ...
                else { next(action); return }

            // Continue refreshing search first
            next(action)

            guard reloadingDisplayedNoteIsNecessary() else { return }
            
            dispatch(DisplayingNote(identifier: identifier))
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment