Replies: 63 comments
-
@Lab3l Presumably this is in the renderer process, or are you using thunks in the main process via the dispatch helper? Or both? When you say "inside getValue1 and getValue2 are async actions" - what does that mean? are you dispatching nested thunks? Any detailed, specific example would be helpful, or preferably a minimal reproduction repo that illustrates the exact problem you are facing. |
Beta Was this translation helpful? Give feedback.
-
This happens with dispatching thunks in renderer process via useDispatch(window.zubridge) |
Beta Was this translation helpful? Give feedback.
-
Ok I think I might have an idea about what's going on here. I'm making a breaking change to the interface (#89) so will get some v2 prebuilds out later and the fix for this should be in there. Also just a note, you don't have to pass handlers into |
Beta Was this translation helpful? Give feedback.
-
So does that mean you don't need the reproducible repo? This is a deal breaker at the moment for us as the hackish "fix" was extremely unreliable on our production testings and provided a really bad user experience so I'm eagerly waiting for the prebuilds to try them out! |
Beta Was this translation helpful? Give feedback.
-
No, I think I've worked out where the issue lies - basically we were only testing trivial thunks and there needs to be logic around ensuring the sequencing in async thunks where you are performing multiple dispatches. I'm adding a logging component to test sequencing, adding E2E tests for this case which should break and then applying a fix. |
Beta Was this translation helpful? Give feedback.
-
@Lab3l I've released the first prerelease, you can install it via the |
Beta Was this translation helpful? Give feedback.
-
Fetched the 2.0.0@next, but I'm now getting errors from my preload script with that version. |
Beta Was this translation helpful? Give feedback.
-
I think it is a bundling issue, the E2Es aren't set up to catch these yet. I released I will have to release a UPDATE: |
Beta Was this translation helpful? Give feedback.
-
I assume that's 2.0.0-next.1 & 2.0.0-next.2? If so, facing the same errors in console with these |
Beta Was this translation helpful? Give feedback.
-
Yes that's correct, I updated my comment. Well, looks like it's more involved than I thought... |
Beta Was this translation helpful? Give feedback.
-
@Lab3l Ok one more release before I have to get on with other things, try |
Beta Was this translation helpful? Give feedback.
-
Unfortunately still happening with 2.0.0-next.3 as well |
Beta Was this translation helpful? Give feedback.
-
Ok last attempt - AI led me down the wrong path but I verified locally that uuid wasn't being bundled correctly, now it looks like it is. Try |
Beta Was this translation helpful? Give feedback.
-
Still the same issue with 2.0.0-next.4 as well |
Beta Was this translation helpful? Give feedback.
-
Hmmm well, I spun up a new electron-vite repo and it seems to work there. Are you sure you have that version? |
Beta Was this translation helpful? Give feedback.
-
Coming out of my tunnel vision, I just realized that here's a simpler way to reproduce the problem. Even dispatching an async action from renderer will cause the same behavior. So basically having a function run in renderer via from a button click
Actual behavior
|
Beta Was this translation helpful? Give feedback.
-
Random gym thought - I removed the auto subscription from the bridge, so you have to instantiate the bridge first then use the returned subscribe method to subscribe windows now. Not sure if I mentioned it earlier or if you've already updated your repo but not subscribing windows isn't going to help matters, haha. |
Beta Was this translation helpful? Give feedback.
-
That's great, another E2E right there. Looking back at this thread I see where things got confused, we've not been disambiguating between dispatches from within a thunk and from outside a thunk. I also thought of another edge case we need to test, starting a thunk from one window and then starting another one from a different window whilst the first is in process. What is the desired behaviour there? I'm thinking defer the second one until after the first one is processed, not sure if this is what happens right now. We will need to update all this logic for selective updates anyway as we want thunks and actions affecting a different part of the state to that of the "in process" thunk, to be let through. |
Beta Was this translation helpful? Give feedback.
-
In an ideal world the queueing system would be the best solution I think, i.e. FIFO the dispatches 🤔 |
Beta Was this translation helpful? Give feedback.
-
This is the current queueing system, it's a priority-based queue with specific logic around thunks (e.g. defer actions when a thunk is in flight - I implemented this after misunderstanding the issue here).
I think you're getting into the realms of more existential questions around side-effects, store structure and overall app architecture when using state management solutions, which is obviously not something that Zubridge should really be concerned with, given that it's basically just a neat way to get your state across the IPC boundary. One of the problems this library will have as it gets more popular is people dumping their random Zustand state issues and poor architectural decisions at my door, it's inevitable 😅 I personally came to Zustand after a long time working with (and getting frustrated by) Redux. That sounds like a bad thing, it's not - I believe Zustand is a lot easier to work with if you've already become accustomed to the more rigid, opinionated, boilerplatey way of doing things that is involved with building on Redux / RTK. Zustand is a lot more fluid and easy to use but I do have a feeling the unopinionated approach may more readily lead to footguns. The reason why I said action handlers shouldn't dispatch further actions is this Redux architectural norm: https://redux.js.org/style-guide/#reducers-must-not-have-side-effects Ideally each action handler / reducer that you use should do just one thing, which is update the state in a limited way. If you want side effects and sequenced events then you typically don't do that as part of your store handlers. Your example of a handler which kicks off multiple actions is basically a thunk. Now thunks aren't special, they are just async functions which kick off a series of state actions based results to other actions and / or side effects, you can easily use the Zubridge dispatch hook and getState to roll your own:
This is effectively what Zubridge was doing internally, at least before you opened this issue. Now it does a hell of a lot more. With all that said, I'm not here to tell you how to structure your app, state or store handlers. Zustand is unopinionated for a reason and it's a lot more fluid than Redux / RTK, all of this is my opinion and you can do what you like. There's likely a few cool ways of using Zustand which I haven't appreciated yet, maybe also I'm overstating an architectural principal which makes sense for Redux but doesn't apply in quite the same way to Zustand. I'd recommend asking in the Zustand Discussions about best practices in this area... Anyway to get back to this never-ending issue, I forked your repo and submitted a PR to fix some random stuff that I found and ensure your windows will be subscribed. If you could try again with this code, I'll try to work out why the E2Es are failing and also implement the new E2E as described above. Once this works we will then need to look at the behaviour around dispatching a thunk whilst another thunk is in process elsewhere. |
Beta Was this translation helpful? Give feedback.
-
Got the E2Es passing locally, working through CI flakiness. Still a long way to go before v2 but I can see the end of this thunk / action handling stuff now. Did another prebuild. I'll add a section in the docs about async handlers support seeing as they seem to work fine now... |
Beta Was this translation helpful? Give feedback.
-
Reworked the thunk management completely, that action queue was doing way too much so I pulled it apart. The global thunk locking seems to work well across all contexts now, you can try it out in EDIT: Changed my mind, doing selective updates / subscriptions instead as it will likely significantly affect how the force mode is implemented. |
Beta Was this translation helpful? Give feedback.
-
Took a small hiatus, back at it again. I agree with what you said. I agree with what you're saying about thunks being the same as what I mentioned when dispatching actions inside reducers, no argument there :D 1: import { debug } from '@zubridge/core'; ✘ [ERROR] No matching export in "node_modules/@zubridge/core/dist/index.js" for import "debug"` |
Beta Was this translation helpful? Give feedback.
-
Looks like there was some glitch in the publish workflow and |
Beta Was this translation helpful? Give feedback.
-
Without adding @zubridge/types to dependencies on next.14 I'm getting an error |
Beta Was this translation helpful? Give feedback.
-
Goddamn, this is why I need to find time for #76 and some package tests 😓 |
Beta Was this translation helpful? Give feedback.
-
Try |
Beta Was this translation helpful? Give feedback.
-
Converted to a discussion as I've fixed the async issue, this is now about getting v2 ready. |
Beta Was this translation helpful? Give feedback.
-
I think we start #76 next and get package tests done. |
Beta Was this translation helpful? Give feedback.
-
Released |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm struggling with async thunk actions and their actions not being reflect on rendered side.
If I have a thunk with multiple dispatches, e.g.
export const thunkadoo = async () => { await dispatch('general.getValue1') await dispatch('general.getValue2') }
and inside getValue1 and getValue2 are async actions that take x-amount of time each, either the thunk is not respecting the awaits or dispatching an action is not updating the store values correctly on subscribed windows. I've hackishly "solved" this by wrapping my dispatched with an async wait when dispatching async actions, but this is inevitable creating more and more problems now that we're closing in on production use.
To expand more on the written example, let's say my getValue1 and getValue2 update general.counter to a random integer. The visible react renderer will not be showing the latest value getValue2 has set and instead will not display any changes or will display getValue1's set value instead of the later getValue2's set value
Beta Was this translation helpful? Give feedback.
All reactions