I can't seem to find any material on the pros/cons of using a functional component as a container component, now that state isn't an issue.
Edit: This is given that most, if not all container components I've come across are class components. Rephrasing this in the form of a question, given the context of container components, would it be beneficial to use functional components as opposed to container components?
First of all, React Hooks and useState are a very new feature to React (class components were the norm for the last 3 or 4 years, as opposed to a few months for hooks), so most documentation and examples are naturally written using class components.
Second, in my personal experience and as it is written in the official docs, there is really no hurry whatsoever to run away from class container components, especially since a well-written, bug-free code is more important than the most optimized, up-to-date code.
The devs in our company are used to class components for containers (we have a 300,000 LOC React application and 100 million users, so changes are not to come just because yes -- if something breaks we are usually in deep trouble).
And, for now, Class Components allow us to easily answer these questions quickly:
Where is this container checking for changes? Check ComponentDidUpdate()
Are there any memory leaks or unhandled events? Check ComponentWillUnmount()
What are the state variables used in this container? Check the constructor()
I have slowly adopted hooks for personal projects and I really like them, but even after playing with them for a few months, many times I can't come up with a "best practice" way of doing and this has been documented in the docs too: best practices can only come with time.
Performance-wise
As for performane, container components are almost never created more than once per page or at most a few times, so I can't possibly think that they would be less performant, provided the code is well written.
Also, benchmarks are mostly just a numbers game (same as CPU cycles and camera mega-pixels), and as posted here by Dan Abramov, seems like benchmarks show similar numbers.
I understand people get obsessed with numbers (when I was really into cameras, I was seriously obsessed with mega-pixels and lens apertures, and funny enough that faded away as my photography skills got better and better).
To sum it up:
Benefits of Class Containers:
More solidified best practices and a lot of good solid information out there.
Tried and tested by many big companies and vouched by developers.
If you like class syntax (I do) in Javascript, class containers make the code more legible.
Benefits of Functional Containers (with hooks):
Cleaner code (no more if props.fetched !== prevProps.fetched halleluyah!)
Better integration with libraries such as Redux's useReducer and dispatch (the reduction in boiler-plate code, as well as HOCs which I quite dislike is very welcome).
Less error-prone to race conditions and I suspect easier to debug, as they follow a very clear functional paradigm.
Again, this is not by any means the de facto standard or anything, just my personal opinion based on experience. Take what you find useful and leave what you don't. Hope this helps! :)
Related
I know that Redux is a just option.
While thinking about whether to use Redux or not, I was looking for articles about cons and pros, but there were few recent articles. Old articles have content that I couldn't agree with.
The articles say that boilerplate code and performance are cons of Redux. but, Is it true even now?
Encapsulation
In redux structure, I could access any data(No encapsulation). but, I didn't. It depends on the developer's capabilities and I can care about encapsulation as much as I want.
Cohesion
When I used redux, My code had more cohesion. Data mutation logic is placed in the slice for every feature.
Boilerplate code
I indeed have to make code as the redux way in the Redux structure.
I had to write a little more code in Redux structure, but it was a little bit. Rather, more parts can be reused when using Redux.
When we make a controller in the back-end, we make code in a framework-dependent way. There is almost no one who makes the controller from very low levels because of the flexible design.
Performance
I have made views for some complex use-cases using react-redux. but, I could find meaningful performance down. I think it is also meaningless that there is a performance down due to hundreds of KB of Redux packages.
So my question is...
The articles about Redux cons I read were written 2 years ago. Using the Redux toolkit is a standard way now. Boilerplate code still is a con of Redux?
If the performance down is a con of Redux, Could you tell me specific examples? (What kind of project has performance problems when using redux, or the cases that don't use Redux because of performance.)
What is the biggest con of using Redux today? (Except that it's hard)
Any other thoughts or opinions, please let me know.
While thinking about whether to use Redux or not, I was looking for articles about cons and pros, but there were few recent articles
Different patterns and architectures don't have pros and cons in isolation, they only have pros-and-cons in comparison to some other architecture or pattern. So far you've only written about Redux - you need to compare it to something first.
The articles say that boilerplate code and performance are cons of Redux. but, Is it true even now?
Accusations of needing boilerplate code is not a criticism of Redux I'm familiar with. On the contrary, Redux actually reduces boilerplate compared to the older Flux pattern.
Encapsulation: In redux structure, I could access any data (No encapsulation). but, I didn't. It depends on the developer's capabilities and I can care about encapsulation as much as I want.
Blame JavaScript, not Redux. In JavaScript all objects are (generally) visible for the world to see: which I consider a strength because it makes scripts customizable and hackable, whereas trying to customize a third-party Java or .NET library (where object encapsulation is the norm) is very difficult if not impossible.
Being able to access all data in the state store is by-design. In Redux (and React) your state-store is meant to be a normalized representation of your application's data, so it makes sense for it to be entirely accessible. It doesn't make sense to arbitrarily restrict what data a component can read (it's not like you're running untrusted code).
Remember that state in Redux and React is immutable (i.e. you cannot edit the data in-place), so exposing everything doesn't introduce any risks because a misbehaving component cannot edit state in-place.
To be fair, you need to use Object.freeze to make the data truly immutable, which I imagine most people forget to do...
Encapsulation, as a property of a system's design, can be a good thing - and it can be a bad thing. Encapsulation generally makes sense when you need to hide internal implementation details that are orthogonal (or entirely unrelated) to the data that is being modelled, such as a Array<T>'s internal buffer pointers or a Map<K,V>'s hashtable buckets. But consider that in JavaScript those types (Array, Map, etc) are built-ins and you can use them to model your immutable state: you can't see into Map's buckets or Array's internal pointers, so you actually never stopped using encapsulated objects.
Cohesion: When I used redux, My code had more cohesion. Data mutation logic is placed in the slice for every feature.
I think you misunderstand what "cohesion" actually means in this context. I don't see how the fundamental design of Redux and its state-reducers relate to any concept of cohesion.
Boilerplate code: I indeed have to make code as the redux way in the Redux structure. I had to write a little more code in Redux structure, but it was a little bit. Rather, more parts can be reused when using Redux. When we make a controller in the back-end, we make code in a framework-dependent way. There is almost no one who makes the controller from very low levels because of the flexible design.
I cannot fully comprehend the above paragraph: the last couple of sentences have nothing to do with the rest of the text.
That said, I appreciate that Redux and React both require a fair bit of repetitive declarations for reducers, actions, and action-creators, but I wouldn't describe it as "Boilerplate" code because the information-theoretic content of those (repetitive) declarations is still very high.
Performance: I have made views for some complex use-cases using react-redux. but, I could find meaningful performance down. I think it is also meaningless that there is a performance down due to hundreds of KB of Redux packages.
The runtime performance of Redux is unrelated to the size of Redux libraries. You are conflating completely separate issues.
That said, I don't know where you're getting the idea that Redux requires you to have "hundreds of KB" of JS files because my last Redux project had a single redux.js file sized at 25KB, which was minified to redux.min.js which was only 6KB in size.
I assume you're referring to the #reduxjs/toolkit library (which has 210KB of source files, but the runtime redux-toolkit.umd.min.js is only 33KB.
Now there is something to be said about the performance cost of the Virtual DOM features in ReactJS, but ReactJS is not Redux. You're free to manipulate the DOM however you like when you use Redux directly - so this point is moot.
There is also a discussion to be had about the performance implications of having to clone immutable state compared to mutating state in-place, however immutable data has inherent qualities which mean you can safely clone-by-reference rather than cloning-by-value. And because Redux uses a directed (ideally acyclic) object-tree graph to represent immutable state it takes advantage of the fact that references to unchanged child objects can be safely passed to constructors of new immutable state (so, for example, if you have megabytes of data evenly-distributed throughout your normalized state graph, and your action and reducer only changes a single deeply-nested object property, then the only about log n data will be reallocated and copied, instead of the entire graph.
The articles about Redux cons I read were written 2 years ago. Using the Redux toolkit is a standard way now. Boilerplate code still is a con of Redux?
What boilerplate are you even talking about?
If the performance down is a con of Redux, Could you tell me specific examples? (What kind of project has performance problems when using redux, or the cases that don't use Redux because of performance.)
Think about it this way: JavaScript is far, far from being the fastest or most efficient programming language (e.g. the V8 JS engine will consume tens of megabytes of RAM just to run a simple "Hello, World" example script) - given that, I wouldn't worry too much about general performance in JS (...at least nothing beyond ensuring that any algorithms you implement in JS run in O(n log n) time or better).
What is the biggest con of using Redux today? (Except that it's hard)
I'd say the biggest disadvantage is having to put up with questions like that.
Any other thoughts or opinions, please let me know.
People use Redux because they want to ensure the data-flow through their JS code is consistent, predictable, and straightforward to reason about compared to ad-hoc JS scripts that don't conform to any overall general architecture or programming patterns. If you don't need those benefits then you might just be better-off doing writing ad-hoc JS.
I would like to understand more about the best practices for passing props around parents-child in react. the problem comes from having a standard way of doing this in a medium-large project to minimize confusion and technical debts such as performance optimization. So far, I only knew these methods on doing this:
standard prop drilling
Pros: easy
Cons: will become unmanageable in complex feature
utilizing React.Context
Pros: medium difficulty, naturally separate from main component
Cons: more time to write, may be unnecessary for smaller components, will do re renders that will cause performance issues headaches in, for example, large forms.
using global state from 'reactn' module
Pros: easy
Cons: will get unmanageable for large projects that have tons of components, cannot prevent rerender AFAIK.
using Redux
Pros: robust and compatible with firebase (react-redux-firebase, redux-firestore), can prevent rerender using areStatesEqual,
Cons: more boilerplates, more work to do for simpler state management
is there a guideline on standard practices on doing this? what do you people use for medium-larger projects? thanks!
The following answer is subjective!
There are basically 3 categories that I am aware of.
Keep everything local ( For any size of app which doesn't deal with sibling dependencies this will work fine. May cause some prop drilling, though it should be avoided as possible, it's not an anti-pattern. You come with better approaches to handle this i.e. PureComponent, React.memo, shouldComponentUpdate)
Keep everything global(redux/reactN/...) (have not seen this approach in my experience, not recommended in my opinion as requires you to hit central state every time when there is a change)
Keep a mix of both. (Highly seen this in medium to large scale projects, we use this approach with redux)
Choosing an option:
Personally speaking, irrespective of the size of an application one can start with the first approach and add the central state later when required(if you are not sure where to put states).
If you need to manage some state centrally from the beginning it can be added from start(if states are clearly defined).
If you choose any one of the above two approaches, to begin with, at one point in time you would need to decide either go for first-party i.e. React Context or a third party i.e. Redux, ....
You have already stated the pros and cons of these, you can compare and see which one outweighs the others.
For a simple answer from the list you provided I would suggest redux, writing actions and reducers does add a certain amount of overhead, and as react evolved and matured it now seems you can manage large applications w/o the use of redux: https://medium.com/#dan_abramov/you-might-not-need-redux-be46360cf367. But once you get how redux works you will be able to scale with ease. This is a good solution for react-redux beginner-intermediate level devs.
The best suggestion I have for you is to use react only.
useContext and useReducer will get you very far, but it requires an intermediate - experienced development skills. This approach will force you to invest time in data-structure, encapsulation of components and use of advance react patterns. (I would enroll to something like https://kentcdodds.com/workshops/advanced-react-patterns)
Iv'e heard a nomerous of times that it is a good practice to #connect only the top level (smart components) and then they can propogate the props to their lower level (dumb components).
It just seems to me that creating dumb component is still possible when #connect(ing) them - simply you pass them only primitive objects\arguments to be displayed.
Is it a good practice wiring all the components to the store via #connect?
Is there any performance impact?
Any thoughts?
A tweet from Dan Abramov, author of Redux:
Emphasizing “one container component at the top” in Redux examples was
a mistake. Don’t take this as a maxim.
Also read his replies at https://twitter.com/dan_abramov/status/668585589609005056
Dan Abramov addressed that in a post on Medium a couple of years ago:
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.vtq34z4ir
He calls them "presentational" versus "container" components. I find the names weird and confusing, which makes it (even) harder to understand. But the goal, I gather, is to be able to concentrate the application-specific stuff (which includes connection to the specifics of the Redux store) in with your container components.
Presentational components are more isolated from your specific application. They're easier to test independently, because they're lightweight and can be stood up without invoking Redux at all. They stand a better chance of being reused, since they're not connected to the specific data format of your app (or to Redux at all).
Personally, I'm not convinced that the distinction is worth maintaining. Really light-weight, reusable components are usually imported from somebody else. Practically anything you write will end up being tied to the specifics of your data store... since that's the point of you writing it in the first place. Writing truly reusable components, which haven't been written before, is a relatively rare occurrence. If you do make one, it'll be relatively easy to extricate it after the fact. (I'm big on not over-thinking your frameworks, since you tend to get them wrong and have to refactor anyway.)
Still, it's a paradigm directly supported by the guy who invented React, and there's a huge user base out there successfully writing code with it. So I'd go with his opinion over mine, if I were you.
You shouldn't strictly connect ONLY top-level components. Once you start doing that, you'll find that some of them grow very large, and pass around data that they're not actually rendering or using.
The solution to that problem is to connect lower-level components that rely on that unused data. The lower you move in the component tree, the more generic (dumb) and re-usable the components will become.
I've read a lot of heated and contradictory information about this sort of subject and I have no dog in the fight - I have the advantage of an open mind.
Let me walk you through my very informal thought process that led me to think, after using a boilerplate with everything in the relay kitchen sink, that I still needed something like redux.
In more than a few scenarios, sufficient redux boilerplate takes less time and much less thought than the sufficient GraphQL and relay boilerplate
The abstraction of actions in redux is a good thing that keeps many programmers out of trouble by forcing them to separate concerns and to encapsulate the internals of a request / how it works vs the existence of one.
Specifically, if I am making a canvas editor with lots of tools and brushes, it seems like it would take a long time to get started the right way in relay making all those mutators and queries and so on with care for persistence.
But if I say, you know, I don't need my app to know every state ever of everything, without something like redux, there is no alternative to either managing state via some sort of big container object or winging it, both of which are inferior to redux
Therefore my instinct that redux has its place in this scenario is the right instinct
However, I might just not understand how GraphQL and relay are supposed to be used.
Therefore, I am asking for concrete answers about 1) whether this is a fairly objective or subjective question, 2) whether there is a consensus or not, and 3) if I should care.
One more thing - if it is the case that redux is fair game in such a scenario, is it still a good rule of thumb that my app ought to have a single store? Or can I start using redux more modularly and in mroe of an adhoc fashion?
By the way here is a more simple scenario: I want to use a Stepper from material-ui which requires State. Without redux my choices are either to faithfully do that at the relay level or below, wing it in the components, or try to fudge it somehow or mix it. The only sound option is the first, and that takes time.
After doing much research I found out that Redux and Alt are two really popular flux implementations.
I also found that Alt is more of traditional flux pattern and Redux is slightly different from the traditional flux. In Redux, the state is stored as immutable tree which means there will be a new object created for every change.
Now coming to my question, I have a requirement to develop a WYSIWYG authoring platform. This means that the contents of this app will keep changing every few seconds.
So does this mean that using Redux for this app will be a bad option as there will be thousands of objects in the memory as we start editing the content. Is alt implementation a better option?
Which flux implementation makes more sense?
Thank you.
Most of the time you have 2 main areas where front end applications can take a significant performance hit. One is memory usage (as you pointed out) and the other is DOM rendering. As far as memory usage is concern, it would be hard to hit that performance limit, unless you have a memory leak or deal with extremely large data sets. I suspect that neither of these will be a problem for you. Instead DOM rendering and efficient updating should be the focus of your decision. Here you need to look at React more than Redux. Redux utilizes the render mechanisms of React components and this can be highly optimized when encountering performance issues. If you have faith in React performance (and in my opinion you should) then either framework would work in this case.
Here are a few friends :) having a good conversation on the topic (related to Redux): https://github.com/reactjs/redux/issues/634
I haven't seen any evidence that Redux's immutability paradigm is bad for performance. (I don't say that to be rude or dismissive, I would love to see the evidence if it exists.)
Frankly I don't think what you choose as your data layer is a major concern here. In a WYSIWYG app, the bulk of your complexity is going to be in the view layer.
My advice would be to make sure you write your app in a way that the data layer can easily be swapped out and replaced. That way, if you do find your chosen framework is a performance hog, you can easily replace it.
Since the overhead of the flux implementation is not an issue, the best choice would be the implementation that is the most logical to you. You are going to be more productive using tools that make sense to you.