XSM: State management for Angular, React, and Vue
github.com
github.com
setcfg({'framework': 'React'})
I immediately think to myself that the designer of the API either (a) values tiny function names over understandable ones, or (b) hasn't given naming enough thought to be consistent. Either way, it's not a good sign and turns me off from investigating further.The package only exposes 9 functions, and the naming is mostly consistent. There's no benefit to publicly nitpicking function names in something with such a small API.
Edit: for those who disagree and downvote. Not only gp's comment doesn't adress the core issue and is a direct attack to the developer, but it cannot even be accepted as valid and helpful criticism. His point b says that it is possible that the developer doesn't value consistency, while his point a says he might be consistent with short naming. These remarks make it look more like random possible remark than ones that are really specific about this project.
Maybe that just escaped you from some reason, but I would think it's perfectly understandable for just about anyone.
Curious if anyone else here had a hard time parsing it...
Since it only has hard-coded support for 3 frameworks, there's no benefit to using magic strings, it would be preferable to use a typed API like:
XSM.useReact({ ... })
Where you can provide fx-specific options for each fx it supports. It also hides all the config options available behind a generic API which you have to dive into the impl [1] to see what options are available and what args each config option supports. Everyone would be far better off bringing all config options to the API Surface area, you could easily type-check all options in TypeScript which ensures correct usage of the API and let you know of any additions/removal or breaking changes.https://github.com/peterluhub/realworld-example
It implements the Realworld Example App specs. The state and API logic are factored out into an NPM package(rw-xsm-handlers). The intention is to use the same code(state management and API) for all the XSM supported frameworks to implement the Realworld Example App specs.
The React example is finished. Angular and Vue will be added later.
I kinda missed the big picture here.
If you want to write code that targets multiple JS fx's you're better off with a well thought out proper solution that lets you develop components that you can use in all major components like https://stenciljs.com or alt solution that lets you target Web Components.
You state management shouldn't really have all your api calls in it. Especially if you're worried about cross platform, put your api interface code into a library, call that from components or your state management. If you find your state management code seems to exist only to call out to your api, it's probably not global state in the first place.
Approximately 90% of the time, when people are posting questions about VueX, my first thought, is 'that really doesn't seem like global state'
Most of the time yeah I do use Redux (sagas) to query my API and store the result. Many of my components need access to the same data (who's the current user, what's their list of items, what's the current item being looked at...), so it's at least shared state if not global
Things like the current user are 100% global state.
A list of user settings, or valid values for a dropdown that doesn't change often (like a list of timezones, or countries), totally global state.
A list of objects only shown on one page or in one component? That component can call an api library for the data itself.
State of a component? Definitely not global scope. Specific example; virtual scroll for a table. storing the offset as global scope. As soon as a second instance of the component was loaded on the same page there would be major issues.
Data that gets paginated should probably not be in global state, or cached heavily, depending on the app. A couple dozen entries is fine, but the idea of pulling every record in a list from say, an erp app, and then paginating in memory, would wreak havoc on a user's browser. And you're keeping that in the browsers session memory. Not to mention ramifications on the backend, even if it is cached. and then you need to deal with cache invalidation, and then...
Better just use React all the way.
You can do much cleaner job using React hooks.
https://redux-starter-kit.js.org
It's also written in TypeScript itself, so it works well for TS usage. It doesn't do as much strict magical inference as something like `typesafe-actions`, but it should be very usable.
I recently wrote a small example "Github issues" app that's written in TS and uses Redux Starter Kit and our new React-Redux hooks API, if you'd like to see how the code looks:
https://github.com/markerikson/rsk-github-issues-experiment
In particular, here's an example of RSK's `createSlice()` API in action, with TS and some thunks:
https://github.com/markerikson/rsk-github-issues-experiment/...
This looks very nice though, avoids almost all the repetitions you usually have to write when setting up reducers and actions!
And yes, as part of our planned docs revamp, we're going to write example code that is much shorter, including use of Redux Starter Kit by default and use of the "ducks" pattern and/or "feature folders" by default.
Could you leave a comment at https://github.com/reduxjs/redux/issues/3313 with some notes on how the current docs examples are too verbose?
If you're willing to wait a week, I could share. I'm really not ready to share it as is (still working on the code).
> Could you leave a comment at https://github.com/reduxjs/redux/issues/3313 with some notes on how the current docs examples are too verbose?
Yes, I could do that, but again I'll need at least a couple of days. It's a crazy week for me.
If you want a _quick_ example, here's one from the 'actions' section of the basic tutorial:
------
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
------I would advocate writing this as:
const addTodo = (payload) => ({
type: ADD_TODO,
payload,
});
-------4 lines instead of 6, just as readable to me. And frankly, I'd consider doing that as a 1-liner since there's only two attributes in the action anyway. Where I work, we have a semi-official rule of 'newlines for attributes if there are more than 3, or if the line length > 80', so our policy would write this action creator as a single line.
export const addTodo = payload => ({ type: ADD_TODO, payload });
For that example, it's a combination of:
- ES6 was barely finalized when the docs first came out
- Questions of clarity and familiarity with arrow functions.
Fortunately, with Redux Starter Kit, you don't even have to write action creators or action types by hand any more :)
It's really easy to get the feeling EVERYTHING needs to go into global state management, from variables used once in one component on one page, down to loop counters.
The simplistic contrived examples exacerbate this. A list of todos doesn't really need to be in global state. An auth system would though. However, all the examples only show things like list views or a detail view, that don't need to be globally available.
Of course, if your app is already built on redux, that doesn't mean refactoring away from it should be a business priority, but new projects should avoid it.
> If your back-end is something like a wire protocol over ws where you've already structured everything as "actions" or "messages" it's a decent fit
Redux has been fine for every API I've every used. Maybe you've only seen crazy codebases where people write a unique action generator/action_type/reducer for every single endpoint, but that isn't exactly a problem with Redux.
I have a lots data that needs to be globally available between multiple pages and is largely interdependent (i.e. one update might affect multiple slices of the data). The data needs to be updated optimistically (i.e. we show updates to the user before the fetch succeeds and unwind if it fails) and the updates are triggered through a mix of web socket polling and user actions.
You're right that I don't need Redux for this project, but oh boy I really like using it.
This is the ideal use case for react context. It's not as if redux is doing something magical to achieve that result, it uses context under the hood anyway, but it adds on the complex and usually unnecessary action/reducer abstractions. I have mentored about two dozen developers on react and redux projects over the past three or so years, I've learned this lesson the hard way.
> the data needs to be updated optimistically (i.e. we show updates to the user before the fetch succeeds and unwind if it fails) and the updates are triggered through a mix of web socket polling and user actions.
Redux doesn't address these problems specifically, but I'd be curious to understand why you think redux is of particular value for them.
> You're right that I don't need Redux for this project, but oh boy I really like using it.
Well that's fine, I'm not arguing that you shouldn't use what you like.
Not really. React.Context solves the global availability bit but it does not scale with the size and complexity of your data. You'll end up building a custom Redux store inside your Context anyways, except now with an uglier API and no devtools.
Alternatively, you could just use a bunch of independent React Contexts, but that becomes unmanageable quickly especially if the Contexts are interdependent.
> Redux doesn't address these problems specifically, but I'd be curious to understand why you think redux is of particular value for them.
The action/reducer model is a very natural way of modeling it. The business logic and data fetching layer is completely disjoint from the actual data store. We can simply describe what happened -- hey, we tried to post this data, this request succeeded, but this one failed and here's the error message -- and then let the reducers decide how that updates their state, if at all. It makes it much easier to refactor code and add new features, especially when they can just hook into existing actions.
Even if I didn't use Redux -- and to be honest I don't love the API sometimes -- I would follow the Redux patterns. When done well it's a really seamless way of managing data that would otherwise be a lot of ugly business logic spaghetti.
> have mentored about two dozen developers on react and redux projects over the past three or so years, I've learned this lesson the hard way.
If you're mentoring novice developers I don't doubt the apps they were working on didn't necessitate Redux. It's a powerful tool but it comes as a price, which is why as much as I like it I avoid recommending it to people (especially junior developers) unless they have a really good case for it.
Also, see the other comment I left for discussion on using Redux Starter Kit to simplify that code ( https://news.ycombinator.com/item?id=20501773 ).
* inconsistently named action creators defined in the same file(sometimes) as the actions
* confusing tests that I still don't understand
* the main focus being on axios requests handled in reducers rather than reducers themselves
* the two main reducers being updateData (which merged in object into the store and saveData which fired off the axios request, and every component had to implement custom logic around using these two. Connects everywhere (which a child comment warns against!)
Don't think anyone working on it had made any one decision badly - just a combination of using a new tech in a slightly non standard setting, deadlines, and a strange backend integration.
Also, I don't think any of it was Redux's fault. That link looks good, thank you, will try it out and see if it is similar to what I came up with on my own for this new project.
Edited for spacing
I do strongly disagree about the "`connect`s everywhere" thing, though. We generally recommend connecting more components, not just a few at the top.
A unique action generator, action type, and reducer for every endpoint is the common failure mode (probably because thats what the docs do). Also, the react-redux bindings are a truly horrific API - only call connect where you absolutely must (you can can actually call dispatch on the store if you have a reference).
You might want to read my "History and Implementation of React-Redux" post [0] to understand why `connect` is written the way it is, as well as watch my recent talk "A Deep Dive into React-Redux" [1].
FWIW, we do now have a hooks-based API as well [2]. Do you feel that looks any better?
In general, we recommending connecting _more_ components for better performance [3], and recommend _against_ importing the store directly [4].
[0] https://blog.isquaredsoftware.com/2018/11/react-redux-histor...
[1] https://blog.isquaredsoftware.com/2019/07/blogged-answers-th...
[2] https://react-redux.js.org/api/hooks
[3] https://redux.js.org/faq/react-redux#should-i-only-connect-m...
[4] https://redux.js.org/faq/store-setup#can-or-should-i-create-...
`connect()` is a function that takes 4 optional arguments. The first one is a function, the second is an obj or a function that returns an object, the third is a function that takes 3 arguments that returns an object, the last is an options object that takes up to 7 params (four of which are functions)! Unfortunately, you aren't done yet, because connect returns a function! You pass your new function a component and it returns a different one. Now, you have something you can use! That is the most complicated interface I've ever seen in any library.
`connect` makes code much harder to understand for what seems to be a simple task - wire some data into a component when the data changes.
> Do you feel that looks any better?
Yeah!
However the hooks api is excellent for this.
You can also write custom hooks that pull data from redux and other sources (in my case, root level props passed from another(angular) app, that I made available using Context.
I think that depends on how you're scoping 'redux'. There's certainly a world of difference between saga, thunk, and observable.
....eventually.