6 ms·
The bit I love about the Elm Architecture that I really wish existed in other frameworks is the "Command" system, by which the "Update" step can dispatch furthe
by avolcano 8y ago
The bit I love about the Elm Architecture that I really wish existed in other frameworks is the "Command" system, by which the "Update" step can dispatch further changes. Basically, imagine if a Redux reducer could dispatch further actions.
I've tried building Redux apps with bidirectional real-time communication (re: networked video games), and found myself having to pull almost all of the logic up to the action layer, as I often needed to dispatch further side effects based on changes that happened as the result of an action. It made my reducer into nothing more than a dumb setter, and caused me to have to write complex mocked tests for my action layer instead of my reducer layer.
I know there's been some attempts at bringing this to Redux (such as https://github.com/redux-loop/redux-loop https://github.com/redux-loop/redux-loop), but from what I've seen it isn't quite as easy to use.
OTOH, I will say, as an outside observer, it sounds like Elm has run into problems with this approach (see: the removal of WebSockets from this guide, pending a rewrite), so I am curious to know more about what issues arose.
- bcherny 8y agoCheck out Undux effects - they're exactly that. https://undux.org https://undux.org
- kiliancs 8y agoredux-loop is harder to use, but so is Redux itself. They are both having to fight the language (JS) to do what is so simple in elm.
- rtfeldman 8y agoTo be fair, the websocket package's design problems are unrelated to the Elm Architecture - just plain old run-of-the-mill API challenges. :)
- mudetroit 8y agoredux-observable can give you something rather akin to that type of behavior. It sees each action after it has already been applied to update state. This also separates out the reducer from those side-effects, which you really want anyhowto keep your reducers as pure functions.
- the_duke 8y agoredux-saga makes implementing a pattern like this pretty straight-forward. You can have sagas subscribing to actions and processing them in arbitrary ways, including dispatching new actions.
- bauerd 8y ago>Basically, imagine if a Redux reducer could dispatch further actions. You can achieve the same by using redux-saga[0], then writing a generator function ("saga") that inspects dispatched actions, and potentially triggers a side effect, dispatches another action, waits for another action to get dispatched in a certain time, etc. [0] https://github.com/redux-saga/redux-saga https://github.com/redux-saga/redux-saga
- EduardoBautista 8y agoI really wish the React ecosystem had less dependencies. Things that are included in other libraries are always met with “You can always install X” as if it were a good thing to add more dependencies.
- wereHamster 8y agoMaybe you want to use react with something other than redux, or saga. Now you say: it doesn't matter, if there is any dead/unused code it will be removed during bundling. That's indeed true. But then, shouldn't we simply install all packages that are available on npmjs.com, and never think about dependencies again? Or don't install any and let our editor or bundler install dependencies automatically? If installing dependencies happens automatically as soon as you write an import statement, does it matter anymore whether you write `import Redux from "redux"` or `import Redux from "react/redux"`? Hardly…
- boubiyeah 8y agoSome people's package.json is the stuff of nightmares
- jnbiche 8y agoI wish NPM were more secure, but I'm glad that the ecosystem uses small libraries. Many people don't need library X for their React/FrameworkX/VueJS project, so including it in the framework just results in additional bloat for them. Extra bytes are not a trivial issue for frontend web development, like they are for many server projects.
- craigts 8y agoYou should take a look at mobx-state-tree. It provides this capability in a straightforward way and is more approachable in general.
- jarcane 8y agoHyperapp can do something like this. You can have an action that sends a message for another action. This is how it handles asynchronous HTTP requests for instance: the http() function takes both the URL/params for the request, and the name of an action that will receive the response as an argument. The result feels very Elm-like, albeit sans the assurances of the typing.
- yogthos 8y agoThe re-frame effects in ClojureScript are a similar idea https://github.com/Day8/re-frame/blob/master/docs/Effects.md https://github.com/Day8/re-frame/blob/master/docs/Effects.md
- baddox 8y agoI think Redux middleware is the answer to this. My preferred approach is to keep all my actions as simple serializable objects, and have (potentially many) small middlewares that listen for certain action types and perform async tasks and dispatch further simple action objects. There are also more fully-baked middlewares like Redux Saga, but I find that those are a bit too heavy-handed and result in too much “lock-in” for implementing your actions and action creators.
- russellbeattie 8y ago"Imagine if a Redux reducer could dispatch further actions." I use a technique called "actors" that are like non-UI components that listen to store events and dispatch additional actions if necessary, using setTimeout so they're pushed to the end of the event loop. Some pedants online continually claim this - or something like it - is an "anti-pattern" but I'm trying to get stuff done, and this is the way to do it.
- okbake 8y agoNGRX (the redux inspired state management library for angular) has a concept called 'effects', which lets you subscribe to the action stream (actions and the state in ngrx are both rxjs observables) and trigger side effects in response to certain actions. The effects themselves map to one or more actions (or zero if you want side-effects only) when they are finished that get dispatched. Since you're dealing with them from within an observable stream you have access to all the rxjs operators, so you can do things like waiting for multiple actions to be dispatched before doing something, etc.