I have used immer in the past and really enjoyed it. It makes using redux a breeze. I recently found out about normlizr and it looks great as well.
What is the difference between the two? Does immer provide the same normalized solution as normalizr? What is the better choice out of the two for a production app? Or should they be used together?
They're two completely different tools, and may be used together.
Immer is a library for performing immutable updates to data while writing "mutating" syntax.
Normalizr is a library for taking nested data of multiple types (such as a Post that contains a User and Comments), and extracting them all to a set of normalized lookup tables.
Both of them are commonly used in Redux apps.
Our official Redux Toolkit package already has Immer built-in. RTK also comes with a createEntityAdapter API for storing and updating normalized data, which uses Immer internally, and we specifically have a usage guide section on pre-processing response data with Normalizr and then handling it with createEntityAdapter
Related
According to Redux Style Guide, it is strongly recommended to connect more components to read data from the store.
For example, rather than just connecting a <UserList> component and reading the entire array of users, have <UserList> retrieve a list of all user IDs, render list items as <UserListItem userId={userId}>, and have <UserListItem> be connected and extract its own user entry from the store.
This, though, sounds a bit contradicting to what has been encouraged earlier in "Usage with React" section to separate presentational components from container components where the presentational components are to read data from props, not from the store.
Does this mean that:
It is best practice to keep the number of presentational components to minimum, hence increasing the number of stateful components?
Or the connected components can also be actually stateless components?
I'm a Redux maintainer, and I wrote the Style Guide page.
The short answer is that the Redux docs have been written over time, and thus some of the older docs page are out of date.
The Style Guide is our latest and current advice on how you should write your app.
We're in the process of rewriting the Redux core docs. That exact "Usage with React" page is something I intend to rewrite very soon, and when I do, I'll be dropping the terms "presentational" and "container" entirely.
I'd also encourage you to read my post Thoughts on React Hooks, Redux, and Separation of Concerns and watch my React Boston 2019 talk on Hooks, HOCs, and Tradeoffs to get some more thoughts on how hooks change the way we think about writing components.
Like everything in programming, there is a balance.
On the one hand, you have separation of concerns, making sure each block of code is focusing on one task. This can help reduce the complexity of a given component.
On the other hand, you have reduction of parameters, reducing the brittleness of your code by keeping track of fewer parameters at any given moment.
The first bullet is typically required when your state management is complex, or you have to manage server connections, and want to keep that work separate from the presentation to reduce confusion.
Redux takes care of that for you, by putting that code into the reducer. If you use the connect() higher-order component, that's exactly what you're doing: creating a component to translate state for your base presentation component. The useSelector() and useDispatch() hooks are another way of reducing the state management code in your component.
Redux stresses the second bullet because Redux's purpose is to reduce the clutter to the point that you don't need to separate your code into presentation and business logic components. Instead of passing several props back and forth, you can pass a single key, make a simple function inside your component to retrieve the data, and get on with the presentation directly.
The folks who wrote Redux also want to reassure folks that Redux is quite fast, and not to be afraid to use it generously.
My own experience is that Redux manages the business logic side of things well enough that I rarely need to create a separate wrapper component for business logic. The state code is a few lines calling hooks at the top, and that's it.
If I do have complex business logic, typically it involves deciding what state to display. That involves determining which key to use in my Redux state. So I might put all that logic into a wrapper, but the end result of the wrapper is a single key that my presentation component uses to pull the appropriate state from Redux.
Should I just copy the database relationships, or are there good patterns to follow? In the Redux documentation it says that the tables should not be a lust but objects mapped by it's ids, and also have a list containing all IDs. It does not provide any example of how it can be useful though. I've seen some other random designs... What design is the most accepted in the community?
For managing normalized reducer state, use normalized-reducer. It's a higher-order-reducer that takes a schema describing the relationships, and returns a reducer, actions, and selectors that write/read according to the relationships. It also integrates easily with Normalizr and Redux Toolkit.
I have been using Vuex for awhile now, and I have always been following the pattern: Components use Actions to commit Mutations to mutate the Store. I thought this was the proper way to do things considering this diagram from the docs:
I came across code where people were committing mutations directly in components, and not even creating simple actions which have no purpose other than to trigger mutations. I even found several examples of this in the Vuex docs.
I figured since it's used in the docs this must be an acceptable pattern, and I was wondering if skipping Actions and directly triggering Mutations was a pattern endorsed by any other state management libraries such as Redux of Flux itself.
TLDR: Is it ok to commit mutations directly in Vuex, and if so, do other state management libraries such as Redux use a pattern like this? If so why don't they?
Just keep in mind that mutations have to be synchronous. You can commit directly in components if you (and your team) are sure is there no chance of appearing of something async. In other words, use it with simple and direct operations.
Committing only in actions as a rule adds some clarity and reliability to application's code.
I didn't used Redux, but as far as I know, some state managers have middleware.
Using mutations and action (Vuex-way) may cause a difficult maintenance into large applications.
In the future version of Vuex, mutations and actions should be merged into the one entity.
Similar discussion: https://github.com/vuejs/vuex/issues/587
Good topic here!
Actions are for more complex logic functionality specially async,
but mutations on the other hand are for changing the state .
And is totally fine to commit mutations from within your component!
(best practices are outdated by time, most of the time anyway)
I come from a background in embedded systems where you're really careful about memory management. With Redux especially its concept of immutability.
So let's say I'm modifying a member of an array. I have to create a new array that links to all original members plus the modified item.
I understand why using Immutability improves the speed but my question is since we essentially never remove the old copies of the objects and create new ones, Redux still keeps a reference to the old objects because of time traveling features.
Most machines these days have quite a lot of memory, but shouldn't at least in theory the Redux app crash because the tab/process runs out of memory? After a long use maybe?
No. First, Redux itself doesn't keep around old data - that's something that the Redux DevTools addon does. Second, I believe the DevTools addon has limits on how many actions it will track. Third, Javascript is a garbage-collected language, so items that are no longer referenced will be cleaned up. (Hand-waving a bit there, but that generally covers things.)
Immutable.js leverages the idea of Structural Sharing while creating new copies of collections. It implements persistent data structures and internally uses concepts like tries to implement structural sharing. So, if you created a list with 10 items, adding a new item to it will not create a new list.
Persistent data structures provide the benefits of immutability while
maintaining high performance reads and writes and present a familiar
API.
Immutable.js data structures are highly efficient on modern JavaScript VMs by
using structural sharing via hash maps tries and vector tries as
popularized by Clojure and Scala, minimizing the need to copy or cache
data.
I suggest you watch this awesome talk by Lee Bryon, Immutable.js creator
I started Meteor a few months ago.
I would like to know if using cursor.observeChanges for buisness objects is a good idea
I want to separate operations and views so I can uses the same operations in many views/events, and I want to know if it is a good idea.
Someone told me, we should not separate operations on mongo from view.
So my question is : Is it a good idea to to Buisness Objects with Meteor ?
Tanks for reading me.
cursor.observeChanges is essentially what you get behind the scenes when you do normal find() queries and bind to template helpers due to its context being reactive.
In the meteor world, the traditional model/view/controller paradigm is shifted towards a reactive data-on-the-wire concept including features like latency compensation.
What you refer to as a business object is basically a representation of your business data which is strongly typed, has a type of its own, atomic, and has only one task of representing.
You can achieve that kind of separation of concerns in any language/framework, including meteor. That only depends on how you lay out, structure and abstract your code.
What Meteor brings into the equation is the toolset to build up an interface to your data with modern ux features that are otherwise very hard/expensive to get.
The only concern over business-class applications could be the fact that Meteor currently employs MongoDB by default. MongoDB has its own discussions around business applications whether they need transaction support, ad-hoc aggregation, foreign key relationships etc. But that is another topic.