Replies: 8 comments
-
Hey there @runloop! Unfortunately you won't be able to use indirect enum List<A> {
case empty
case cons(A, List)
}
enum Action {
case appendZero
case incrLast
}
func recursiveListReducer(
state: inout List<Int>,
action: Action,
environment: Void
) -> [Effect<Action>] {
switch (state, action) {
case (_, .appendZero):
state = .cons(0, state)
return []
case (.empty, .incrLast):
return []
case let (.cons(last, .empty), .incrLast):
state = .cons(last + 1, .empty)
return []
case (.cons(let n, var list), .incrLast):
let effects = recursiveListReducer(
state: &list, action: .incrLast, environment: ()
)
state = .cons(n, list)
return effects
}
}
let listReducer = Reducer(recursiveListReducer) Hope this gives you enough direction! |
Beta Was this translation helpful? Give feedback.
-
I'm not sure this will work for me. I currently have an entire component that needs to be used recursively where viewing deeper and deeper into more specialised components will be required. I can't see it working with this. Even if it is somehow possible it seems so complicated that it's probably not even worth the effort. If I'm wrong it would be great if you demonstrate something with with more complexity. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure I fully understand the problem. The recursiveness above is only for a single
E.g.: func recursiveStepReducer(
state: inout List<Int>,
action: Action,
environment: Void
) -> [Effect<Action>] {
guard case let (.cons(let n, var list), .incrLast) = action else { return [] }
let effects = recursiveListReducer(
state: &list, action: .incrLast, environment: ()
)
state = .cons(n, list)
return effects
}
let nonrecursiveStepsReducer = Reducer<List<Int>, Action, Void> { state, action, _ in
switch (state, action) {
case (_, .appendZero):
state = .cons(0, state)
return []
case (.empty, .incrLast):
return []
case let (.cons(last, .empty), .incrLast):
state = .cons(last + 1, .empty)
return []
case (.cons, .incrLast):
return []
}
}
let combinedReducer = combine(
Reducer(recursiveStepReducer),
nonrecursiveStepsReducer
) Does this help? It should always be possible to write this kind of raw reducer as a single, monolithic unit, and it should always be possible to decompose that unit into smaller parts. |
Beta Was this translation helpful? Give feedback.
-
Thanks for trying to help. As much as I like the other aspects of this architecture. The Reducer side of it just becomes too complicated. To the point where I'm struggling to understand it at all. I guess I'm just not clever enough to work like this. |
Beta Was this translation helpful? Give feedback.
-
@runloop Don't give up! Ideally the reducer side of things should be a lot simpler to grok than an object that manages state. Recursion can always be a bit of a mind trip, but we'd love to help you get over whatever hurdle stands in your way. Can you perhaps show how you'd solve the problem in a different architecture so that we can help translate it over to reducers? Or can you flesh out the code you posted above and explain what everything is supposed to be doing? It seems to be incomplete (not all the types are defined in it), and it's unclear to me what you are trying to achieve with the recursion. |
Beta Was this translation helpful? Give feedback.
-
I'll try and explain my situation better. The model is defined so I have less flexibility there. I have a view controller (old speak) which lists the items in a folder. There are a number of different item types, but they are just a set of values. Tapping on an item in the list will take you to the appropriate editor for that item. However, a folder is one of the item types, tapping on a folder in the list will drill down into that folder and display its own items. This can happen over and over again depending on how a user wants to organise their items. That's what this code is trying to represent, I just typed it in here. It's not actual code because I don't know what I'm doing regarding all this. I hope it makes a little more sense. struct Folder {
var name: String
var items: [Item]
}
struct Document {
var name: String
}
enum Item {
case document(Document)
case folder(Folder)
}
enum FolderAction {
case addItem
}
enum FolderViewAction {
case folder(FolderAction)
case document(DocumentViewAction) // actions for editing the document
case subFolder(FolderViewAction) // this was my idea for viewing deeper into the store
}
struct FolderView: View {
@ObservedObject var store: Store<Folder, FolderViewAction>
var body: some View {
VStack {
ForEach(store.value.items) { item in
// navigation link to view item
// need to store.view into a new FolderView
}
Button(action: { store.send(.folder(.addItem)) }) {
Text("Add Item")
}
}
}
} |
Beta Was this translation helpful? Give feedback.
-
Hey @runloop, just yesterday we open sourced the Composable Architecture library, and we have built a case study that demonstrates how this is possible. It introduces a reducer extension method that automates all the recursive stuff: https://github.com/pointfreeco/swift-composable-architecture/blob/master/Examples/CaseStudies/SwiftUICaseStudies/04-HigherOrderReducers-Recursion.swift |
Beta Was this translation helpful? Give feedback.
-
Hi @mbrandonw, thanks for getting back to me. I was in contact with you guys on Twitter about this on Monday. I'm very excited to give it a try. I've checked the Cases Studies project and it looks perfect. What you guys have created here is really something. Great job, and congratulations on the release. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I've been giving the Composable Architecture a try and on the whole it feels great. However, I have run into an issue that I just cannot resolve and it regards components that can contain values of their own type.
In my situation I have a
Folder
component. AFolder
contains a list of items.Item
is an enum where one of the cases isFolder
. So a folder can contain a sub-folder. So I have something that looks like this:Seeing as the reducers are all defined at compile time I just cannot see a way define this kind of structure. I'm probably going about this all wrong.
It would be great if someone could shed some light on this. I can imagine this circular reference situation quite common. Another example I can think of from the top of my head would be user profile that lists friends, which would then view their profile, etc, etc.
Beta Was this translation helpful? Give feedback.
All reactions