-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Redux ‐ How to Implement
roux g. buciu edited this page Sep 6, 2024
·
16 revisions
So you want to add a Redux action and are unsure of what to do. Well, you've come to the right place! For a more comprehensive discussion of Redux in our application, take a look at this bad boy. This page will only be concerned with the nitty gritty details of how to become the greatest Redux-master the world has every known... for your particular feature.
To add a new Redux component, you'll need to do the following things:
- Create an action
- Create a state
- Create a middleware (this is optional, depending on what you're implementing)
- Add the required connections to turn your component into a fully operational battleship
Below, you'll find templates for the work that needs doing.
The action
final class ExampleAction: Action {
override init(windowUUID: WindowUUID, actionType: any ActionType) {
super.init(windowUUID: windowUUID, actionType: actionType)
}
}
enum ExampleActionType: ActionType {
case castMagicMissile
}import Redux
struct MainMenuState: ScreenState, Equatable {
var windowUUID: WindowUUID
var shouldDismiss: Bool
init(appState: AppState, uuid: WindowUUID) {
guard let mainMenuState = store.state.screenState(
MainMenuState.self,
for: .mainMenu,
window: uuid
) else {
self.init(windowUUID: uuid)
return
}
self.init(
windowUUID: mainMenuState.windowUUID,
shouldDismiss: mainMenuState.shouldDismiss
)
}
init(windowUUID: WindowUUID) {
self.init(
windowUUID: windowUUID,
shouldDismiss: false
)
}
private init(
windowUUID: WindowUUID,
shouldDismiss: Bool
) {
self.windowUUID = windowUUID
self.shouldDismiss = shouldDismiss
}
static let reducer: Reducer<Self> = { state, action in
guard action.windowUUID == .unavailable || action.windowUUID == state.windowUUID else { return state }
switch action.actionType {
case MainMenuMiddlewareActionType.dismissMenu:
return MainMenuState(
windowUUID: state.windowUUID,
shouldDismiss: true
)
default:
return MainMenuState(
windowUUID: state.windowUUID,
shouldDismiss: false
)
}
}
}import Redux
class ExampleViewController: UIViewController, StoreSubscriber {
typealias SubscriberStateType = ExampleState
private var exampleState: ExampleState
init() {
subscribeToRedux()
}
deinit {
unsubscribeFromRedux()
}
// MARK: - Redux
func subscribeToRedux() {
store.dispatch(
ScreenAction(
windowUUID: windowUUID,
actionType: ScreenActionType.showScreen,
screen: .exampleScreen
)
)
let uuid = windowUUID
store.subscribe(self, transform: {
return $0.select({ appState in
return ExampleState(appState: appState, uuid: uuid)
})
})
}
func unsubscribeFromRedux() {
store.dispatch(
ScreenAction(
windowUUID: windowUUID,
actionType: ScreenActionType.closeScreen,
screen: .exampleScreen
)
)
}
func newState(state: ExampleState) {
menuState = state
// do stuff here
}
}import Redux
import ToolbarKit
final class MainMenuMiddleware {
private let logger: Logger
private let telemetry = MainMenuTelemetry()
init(logger: Logger = DefaultLogger.shared) {
self.logger = logger
}
lazy var mainMenuProvider: Middleware<AppState> = { state, action in
switch action.actionType {
case MainMenuActionType.mainMenuDidAppear:
self.telemetry.mainMenuViewed()
case MainMenuActionType.closeMenu:
self.dismissMenu(windowUUID: action.windowUUID)
default:
break
}
}
// MARK: - Action Helpers
private func dismissMenu(windowUUID: WindowUUID) {
let action = MainMenuAction(
windowUUID: windowUUID,
actionType: MainMenuMiddlewareActionType.dismissMenu
)
store.dispatch(action)
}
}