Skip to content

Instantly share code, notes, and snippets.

@jayrambhia
Last active May 9, 2019 06:30
Show Gist options
  • Save jayrambhia/45f88628444952bacd674b24d0605bda to your computer and use it in GitHub Desktop.
Save jayrambhia/45f88628444952bacd674b24d0605bda to your computer and use it in GitHub Desktop.
Redux implementation in Kotlin
data class AppState(val searchState: SearchState = SearchState())
class AppStore: Store<AppState>(
initialState = AppState(),
reducers = listOf(::reduceSearchState)) {
companion object {
val instance by lazy {
AppStore()
}
}
}
data class AppState(val searchState: SearchState = SearchState())
class AppStore: Store<AppState>(
initialState = AppState(),
reducers = listOf(::reduceSearchState),
middleware = listOf(::loggerMiddleware, ::searchMiddleware)) {
companion object {
val instance by lazy {
AppStore()
}
}
}
abstract class SimpleStore<State>(
private val initialState: State,
private val reducers: List<Reducer<State>>): Store<State> {
private var currentState: State = initialState
private val subscriptions = arrayListOf<Subscription<State>>()
override fun getState() = currentState
override fun dispatch(action: Action) {
val newState = applyReducers(currentState, action)
if (newState == currentState) {
// No change in state
return
}
currentState = newState
subscriptions.forEach { it(currentState) }
}
private fun applyReducers(current: State, action: Action): State {
var newState = current
for (reducer in reducers) {
newState = reducer(newState, action)
}
return newState
}
override fun subscribe(subscription: Subscription<State>) {
subscriptions.add(subscription)
// notify subscription of the current state
subscription(state)
}
override fun unsubscribe(subscription: Subscription<State>) {
subscriptions.remove(subscription)
}
}
abstract class SimpleStore<State>(
private val initialState: State,
private val reducers: List<Reducer<State>>): Store<State> {
private var currentState: State = initialState
private val subscriptions = arrayListOf<Subscription<State>>()
private fun dispatch(action: Action) {
val newState = applyReducers(currentState, action)
if (newState == currentState) {
// No change in state
return
}
currentState = newState
subscriptions.forEach { it(currentState, ::dispatch) }
}
override fun subscribe(subscription: Subscription<State>): Unsubscribe {
subscriptions.add(subscription)
// notify subscription of the current state
subscription(state, ::dispatch)
return { subscriptions.remove(subscription) }
}
// Rest of the code - reudcers and stuff.
}
abstract class SimpleStore<State>(
private val initialState: State,
private val reducers: List<Reducer<State>>,
private val middleware: List<Middleware>): Store<State> {
private var currentState: State = initialState
private val subscriptions = arrayListOf<Subscription<State>>()
private fun dispatch(action: Action) {
val newAction = applyMiddleware(currentState, action)
val newState = applyReducers(currentState, newAction)
if (newState == currentState) {
// No change in state
return
}
currentState = newState
subscriptions.forEach { it(currentState, ::dispatch) }
}
private fun applyMiddleware(state: State, action: Action): Action {
return next(0)(state, action, ::dispatch)
}
private fun next(index: Int): Next<State> {
if (index == middleware.size) {
// Last link of the chain. It just returns the action as is.
return { _, action, _ -> action }
}
return { state, action, dispatch -> middleware[index].invoke(state, action, dispatch, next(index+1)) }
}
// Rest of the code - reudcers and stuff.
}
class SearchFragment: Fragment() {
override fun onViewCreated(View view) {
super.onViewCreated(view)
// .. initialize views
AppStore.instance.subscribe(::render)
searchButton.setOnClickListener {
AppStore.instance.dispatch(Seaarch(queryEditText.getText().toString()))
}
clearButton.setOnClickListener {
AppStore.instance.dispatch(ClearSearch)
}
}
override fun onDestroyView() {
super.onDestroyView()
AppStore.instance.unsubscribe(::render)
}
private fun render(state: AppState) {
progressbar.show(state.loading)
clearButton.show(movies.size > 0)
searchButton.show(!state.loading)
queryEdittext.setText(state.query)
adapter.setMovies(movies)
}
}
class SearchFragment: Fragment() {
private var dispatch: Dispatch? = null
private lateinit var unsubscribe: Unsubscribe
override fun onViewCreated(View view) {
super.onViewCreated(view)
// .. initialize views
unsubscribe = AppStore.instance.subscribe(::render)
searchButton.setOnClickListener {
dispatch?.invoke(Seaarch(queryEditText.getText().toString()))
}
clearButton.setOnClickListener {
dispatch?.invoke(ClearSearch)
}
}
override fun onDestroyView() {
super.onDestroyView()
unsubscribe.invoke()
dispatch = null
}
private fun render(state: AppState, dispatch: Dispatch) {
this.dispatch = dispatch
// .. rest of the code
}
}
data class SearchState(val loading: Boolean = false, val query: String = "", val movies: List<Movie> = listOf())
object ClearSearch: Action
data class Search(val query: String): Action
data class LoadingSearch(val query: String): Action
data class SearchResultsLoaded(val query: String, val movies: List<Movie>): Action
fun reduceSearchState(state: AppState, action: Action): AppState {
return when(action) {
is ClearSearch -> state.copy(searchState = SearchState())
is LoadingSearch -> state.copy(searchState = SearchState(loading = true, query = action.query))
is SearchResultsLoaded -> state.copy(searchState = SearchState(query = action.query, loading = false, movies = action.movies))
else -> state
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment