1

To make an asynchronous request a middleware is used in this case, it returns an error after a fixed amount of time.

The app state is properly updated the subscriber view controller presents the error.

On the next instance however this subscriber view controller is presented, it finds the error in the state - which is actually the error from the previous request and displays the error message before even the request is fired.

How to go about handling this case in ReSwift/Redux?

Store

    let store = Store(
        reducer: appReducer,
        state: AppState(),
        middleware: [requestMiddleware]
    )

State

    struct AppState: StateType {
        var isRequestInProgress = false
        var result: Result<Bool, NSError>?
    }

Actions

    struct RequestAction: Action {}
    struct ReceiveAction: Action {}
    struct ErrorAction: Action {
        let error: NSError
    }

Middleware

    let requestMiddleware: Middleware<Any> = { dispatch, getState in
    return { next in
        return { action in
            switch action {
            case is RequestAction:
                DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                        store.dispatch(ErrorAction(error: NSError(domain: "", code: -1, userInfo: nil)))
                    })
                default:
                    break
                }

                return next(action)
            }
        }
    }

Reducer

    func appReducer(action: Action, state: AppState?) -> AppState {
        var state = state ?? AppState()

        switch action {
        case is RequestAction:
            state.isRequestInProgress = true
        case let action as ErrorAction:
            state.isRequestInProgress = false
            state.result = .failure(action.error)
        default: break
        }

        return state
    }

The app

class ViewController: UIViewController {
    @IBAction func presentControllerB(_ sender: Any) {
        guard let viewController = storyboard?.instantiateViewController(withIdentifier: "ViewControllerB") else {
            return
        }

        present(viewController, animated: true)
    }
}

class ViewControllerB: UIViewController, StoreSubscriber {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        store.subscribe(self)
    }

    override func viewWillDisappear(_ animated: Bool) {
        store.unsubscribe(self)
        super.viewWillDisappear(animated)
    }

    func newState(state: AppState) {
        showActivity(state.isRequestInProgress)

        switch state.result {
        case .none:
            break
        case .some(.success(_)):
            break
        case .some(.failure(let error)):
            presentError(error)
            dismiss(animated: true)
        }
    }

    @IBAction func request(_ sender: Any) {
        store.dispatch(RequestAction())
    }

    private func showActivity(_ show: Bool) {}

    private func presentError(_ error: Error) {
        print("Error")
    }
}
dead_loop
  • 41
  • 4

0 Answers0