commit 82f2a69289213c15124bd60ea079c38fecd8e173
parent d8cfecf2945ff88835e3a52fe535865b4c9fc903
Author: pollymce <pmceldowney@mozilla.com>
Date: Mon, 22 Dec 2025 13:53:48 +0000
Bug 2005444 - remove ReducerChainBuilder. r=android-reviewers,mcarare
Inline the reducer chain into Store and remove this wrapper class.
It's a bit easier to see what Store.dispatch() is actually doing now.
Also inlining removeSubscription for readability, as it's a one line method that is called once.
Differential Revision: https://phabricator.services.mozilla.com/D277157
Diffstat:
2 files changed, 21 insertions(+), 72 deletions(-)
diff --git a/mobile/android/android-components/components/lib/state/src/main/java/mozilla/components/lib/state/Store.kt b/mobile/android/android-components/components/lib/state/src/main/java/mozilla/components/lib/state/Store.kt
@@ -6,7 +6,6 @@ package mozilla.components.lib.state
import androidx.annotation.CheckResult
import androidx.annotation.VisibleForTesting
-import mozilla.components.lib.state.internal.ReducerChainBuilder
import java.lang.ref.WeakReference
import java.util.Collections
import java.util.concurrent.ConcurrentHashMap
@@ -23,10 +22,10 @@ import java.util.concurrent.ConcurrentHashMap
*/
open class Store<S : State, A : Action>(
initialState: S,
- reducer: Reducer<S, A>,
- middleware: List<Middleware<S, A>> = emptyList(),
+ private val reducer: Reducer<S, A>,
+ private val middleware: List<Middleware<S, A>> = emptyList(),
) {
- private val reducerChainBuilder = ReducerChainBuilder(reducer, middleware)
+ private var reducerChain: ((A) -> Unit)? = null
@VisibleForTesting
internal val subscriptions = Collections.newSetFromMap(ConcurrentHashMap<Subscription<S, A>, Boolean>())
@@ -70,26 +69,24 @@ open class Store<S : State, A : Action>(
*
* @return Unit. Previously this returned a new Job that was launched here, but this no longer happens.
*/
- fun dispatch(action: A) =
- synchronized(this@Store) {
- reducerChainBuilder.get(this@Store).invoke(action)
- }
-
- /**
- * Transitions from the current [State] to the passed in [state] and notifies all observers.
- */
- internal fun transitionTo(state: S) {
- if (state == currentState) {
- // Nothing has changed.
- return
+ fun dispatch(action: A) {
+ synchronized(this) {
+ if (reducerChain == null) {
+ var chain: (A) -> Unit = { action ->
+ val newState = reducer(state, action)
+ if (newState != currentState) {
+ currentState = newState
+ subscriptions.forEach { subscription -> subscription.dispatch(newState) }
+ }
+ }
+ middleware.reversed().forEach { middleware ->
+ val next = chain
+ chain = { action -> middleware(this, next, action) }
+ }
+ reducerChain = chain
+ }
+ reducerChain?.invoke(action)
}
-
- currentState = state
- subscriptions.forEach { subscription -> subscription.dispatch(state) }
- }
-
- private fun removeSubscription(subscription: Subscription<S, A>) {
- subscriptions.remove(subscription)
}
/**
@@ -146,7 +143,7 @@ open class Store<S : State, A : Action>(
fun unsubscribe() {
active = false
- storeReference.get()?.removeSubscription(this)
+ storeReference.get()?.subscriptions?.remove(this)
storeReference.clear()
binding?.unbind()
diff --git a/mobile/android/android-components/components/lib/state/src/main/java/mozilla/components/lib/state/internal/ReducerChainBuilder.kt b/mobile/android/android-components/components/lib/state/src/main/java/mozilla/components/lib/state/internal/ReducerChainBuilder.kt
@@ -1,48 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package mozilla.components.lib.state.internal
-
-import mozilla.components.lib.state.Action
-import mozilla.components.lib.state.Middleware
-import mozilla.components.lib.state.Reducer
-import mozilla.components.lib.state.State
-import mozilla.components.lib.state.Store
-
-/**
- * Builder to lazily create a function that will invoke the chain of [middleware] and finally the
- * [reducer].
- */
-internal class ReducerChainBuilder<S : State, A : Action>(
- private val reducer: Reducer<S, A>,
- private val middleware: List<Middleware<S, A>>,
-) {
- private var chain: ((A) -> Unit)? = null
-
- /**
- * Returns a function that will invoke the chain of [middleware] and the [reducer] for the given
- * [Store].
- */
- fun get(store: Store<S, A>): (A) -> Unit {
- chain?.let { return it }
-
- return build(store).also {
- chain = it
- }
- }
-
- private fun build(store: Store<S, A>): (A) -> Unit {
- var chain: (A) -> Unit = { action ->
- val state = reducer(store.state, action)
- store.transitionTo(state)
- }
-
- middleware.reversed().forEach { middleware ->
- val next = chain
- chain = { action -> middleware(store, next, action) }
- }
-
- return chain
- }
-}