React / Redux: Should containers have any knowledge of state structure? - javascript

This tutorial by Dan Abramov suggests that the advantage to using selectors that act on global state (rather than a slice of state) is that they allow containers to be decoupled from knowledge of the state structure.
If that's the case, shouldn't we also avoid directly mapping state values to props, and use selectors instead? Otherwise, our containers must still know about where those values exist in the state tree.
To illustrate using an example...
Directly maps a nested state value to a prop:
const mapStateToProps = (state) => ({
isModalVisible: state.modal.isVisible,
});
VS
Has no knowledge of state structure. Gets value using isModalVisible() selector:
const mapStateToProps = (state) => ({
isModalVisible: isModalVisible(state),
});
However, the problem with the latter approach is that for each value in the state tree, we have to write a selector. This seems like a lot of boilerplate code just to select a simple value. Is this considered best practice?

The answer for your question is: "it depends"
Do you have a tiny app?
Maybe avoid using redux at all and stick to react components state.
You Might Not Need Redux
Do you have a small app?
Writing a bunch of selectors is a lot of boilerplate just like you said. Avoid writing them and stick to simply mapping, using mapStateToProps.
Medium to large apps?
This is where selectors and memoized selectors pay-off. You'll find yourself checking if modals is visible in many components. Currently in your state modal is under state.modal.visible. But tomorrow a modal might be a part of a parent modal, you'll have to change all mapping in all your components to state.parentModal.modal.visible. You can see how this can turn badly right?
The pros of selectors:
Hides complexity when working in a team.
Changing your state means only modifying your selector function.
Avoid writing filters and reducing lists on each mapPropsToState function.
Pros of Memoized selectors:
Performance.
Cons
Boilerplate code and slower to get started.
Additional libraries.
Hope it answers your question.

Responding to your last comment, yes, it's recommended to write selectors for all values in the tree, even for simple, non-derived value.
Several reasons to do so:
As I mentioned in the comments, once you are using selectors for all the values, you can modify the tree structure as you like and then you only need to modify selectors accordingly. Otherwise you and your co-developer will have to modify every direct mapping mannually, even it's non-derived data.
Decoupling values between different levels in the tree. Like you said, when you have a global-level selector depends on a slice-level selector, e.g. price inside product. When you put product onto somewhere else in the tree, just modify the product selector, and all you global-level selector price will still be fine. I'm not sure Dan mentioned in his tutorial, check this library reselect. It shows the idea between levels.
Efficiency when fetching computed data.
Ofc if you are doing a small project or retrieving simple non-derived values from the tree, you can use direct mapping. But keep in mind applying selectors widely makes your code scalable.

mapStateToProps is the selector. You don't need to write a separate function for isModalVisible necessarily. The idea is mapStateToProps is the only function that needs to know the structure of the global state. You can break down that function if you want, especially as the subs-selectors get more complex, but if all you're doing is selecting a simple value, there's no need to do so.
As a result, the container component doesn't know the state structure. It just knows the structure of the value returned by mapStateToProps. Your two examples are functionally equivalent, as it relates to the question "Should containers know the state structure?". Because in both cases, the answer is "They don't."

Do not mix the local state with the global state (redux store). You can have both on a component but the local state should not depend on global state.
This is due to the following reasons:
It will be hard to test the component
It is a source of more bugs
It will need to keep sync with global state

Related

In React, is it okay to use getElementById, querySelector, etc versus useRef if you don't perform any DOM manipulation?

Specifically used just to view the heights/widths (getBoundingClientRect) of elements. I recently encountered a need to find all the separate heights of a dynamic amount of child elements to perform a calculation. I added a ref within the child component, and passed a function down from the parent in an attempt to update the parent's list of child dimensions (which was in state). I found this to be overtly complex and confusing and unreliable. So, in the parent, I just did a simple for loop with getElementById after giving each child an id of child-${index}.
I know you are NOT supposed to do any direct DOM manipulation in React; however, if your goal is read some data only, then is it an issue or bad practice?
It might not be a problem right now, but I would consider using getElementById instead of a ref bad practice in general (or at least call it "a workaround").
1
getElementById works "outside" of React, so you are not using React here.
That might work for now, but also might interfere with what might do React at some time.
E.g. you might access or hold a reference to a DOM node, and React might decide to remove that node while you were reading it. I don't see why this might happen in your
example, but when using two separate systems it is hard to keep track of the possible consequences.
2
With the id child-${index} you have introduced a logical dependency (coupling) between the parent and the child.
The id child-${index} acts as a reference here, and has to be kept in sync manually.
This might be easier in a short term, but is actually more complex as a general approach (e.g. less maintainable, reusable, ...).
You could say, Reacts whole purpose is to avoid such complexities.
Your components should be as independent of each other as possible, and should only communicate through the props.
suggestion
I suggest to avoid both getElementById and passing a ref, and have the children know their size (e.g. using a custom hook),
and pass only the sizes up to the parent (not the ref).
If that is not possible, I would prefer to use refs.
Also note that "confusion" is not the same as "complexity": Confusion can be decreased by acquiring more information, but complexity is an
inherent property of a system.

React Component State management using redux

So Basically, I came across many articles where they are referring to manage state via flux or redux.
I wanted to know that how about UI component having its own state? Is it good practice to let redux manage the Api call and success toast messages etc. but UI components should have their own local state?
Kindly someone elaborate what is the best practice in industry?
Though the question calls for opinion, I am going to leave my answer. There is no standard best practice regarding this. It boils down to convenience and ground rules of your team, if there are more than one people writing the code.
I use Redux quite a lot. However, I won't refrain from using local state in components.
Form handling like input onChange handlers require local state. It is not performant to use global state for onChange handlers.
Reusable component uses local state. Again, it boils down to whether the reusability is a technical reusability or business reusability. If you are developing a custom scrollbar component, use local state. However, if you are using a comment form which is used everywhere in your application, use global state.
I prefer to have most of the stuff in global state. I use redux thunk as well. In redux thunk, it is possible to access global state within the thunk function. This is quite useful as it avoids the reliance for props / context being passed all around.
I do keep some simple things in local state -- for example, show / hide some stuff. I don't mind waiting for promises to resolve before hiding some stuff using local state.
Overall, the decision to use global state vs local state is primarily based on convenience. There are no standard rules other than what you and your team are comfortable with.
React is a way to declaratively deal with UI. There are some rules of the framework like state, props, context. It is left upto the developer to make the UI declarative and performant based on these primitives. How, a developer does it does not matter as long as the code is maintainable and understood by others.
After asking many professionals and industry developers, I came to know that managing state through redux depends on your application scope.
but more importantly, If I am working on enterprise Application then the application state must be managed through redux.
Now the question is what should be kept in our redux store. well, you can store almost anything in redux store but better to manage the local state of a component as well. for instance, opening a component Boolean should be managed in local state or any string or header name etc.
Good question! The answer is usually "it depends", but there are clear cases when you'd probably prefer to use one over the other.
Use Redux for storing state relevant to the application. E.g. the current page/panel that should be shown. As you mentioned, showing a notification/message - is something that'd make sense to store in redux state, as the alternative would be passing state all over the place, e.g. an error prop bubbling up to your root component which renders the toast message. Using thunk is also a good idea when you're fetching/manipulating data relevant to the whole app, e.g. a list of things that appear in several places.
Use component state for storing state only relevant to the component. That is, if you're filling in a form, it makes sense to store the value of text inputs, checkboxes etc. in your component state (perhaps in conjunction with container and presentational components) as the values at this point aren't relevant to the rest of the application.

Why use setState in React?

If I have a class with a bunch of properties, it seems like a hassle to put the properties that I modify inside (for example) this.state.myProp1 instead of this.myProp1. and then I need to make a copy of whatever property it is before I send it off to setState (because I can't mutate it directly). Like an array of objects for example.
At some point I display some of these properties so that means that I need to hold all my class properties inside this state, and then keep track of what I need to refresh, instead of refreshing the whole thing.
I almost prefer to use this.forceUpdate() instead and have my render() refer to class properties directly. Why does react "make" people use this.state and setState. Is it for performance reasons?
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.
So basically setState is there to tell react when to re-render. Also setState behaves asynchronously, and updates the state only when necessary. So if you call setState multiple times immediately it will update only on the last one so as to minimize the number of re-renders and be less taxing on the browser. If there was no setState and react re-rendered every time the data changed, the browser experience would be terrible.
You don't have to use React this.state and setState if you don't want to. You can always use redux or mobx to manage the state.
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made.
And yeah, that's why you've to make a copy of whatever property it is before I send it off to setState
IMHO, component state is an elegant concept for some special case. for example when you want to monitor the content change of a text input on live, that is, not after hit save or submit button. under such situation, a component state would be ideal place to store the temporary input and you will not get overhead to use redux action to respond on the every incomplete input. it is just like a buffer to provide performance improvement.
1. Reasons behind setState
The main reason for having to use setState is its asynchronous execution, from the react docs:
React intentionally “waits” until all components call setState() in their event handlers before starting to re-render. This boosts performance by avoiding unnecessary re-renders.
If the state object was updated synchronously it would cause consistency issues, since props are not updated until the parent component is re-rendered, so, mutating this.state directly would lead to inconsistency between props and state.
For further reference, you can check this this Github thread.
2. Reasons behind this.state
The main advantage of the state object is its immutability which couldn't be accomplished with component properties, also there is the separation of responsibility between props and state, which is way easier to handle and update individually.
Why does react "make" people use this.state and setState. Is it for performance reasons?
That's a good question - the existing answer from J. Pichardo is quite correct but I wanted to address the why in a little more depth - as opposed to what or how.
Really a better question is - why does React exist? According to this article
React’s one-way data flow makes things much simpler, more predictable, and less bug-prone. One way data flow greatly simplifies your thinking about state because no view can ever mutate the state directly. Views can only send actions up to the global state store.
Really theres a whole bunch of reasons why React has it's place as a useful UI library. But in regards to your question - uni-directional data flow - this is the main reason.
relational UIs get complex. When an app has to consume, display and update even just a modest amount of relational data and have that information displayed across multiple elements, things can get messy fast.
Using state and props the way that React does allows one to differentiate and guarantee whether a piece of the UI will just receive data to display or whether it might change it too.
If you store that data just in a random key you have no real way of knowing whether the value is changed and what changed it. By separating out your state from your component in this way, it decouples the data from the element and makes it much easier to share data between elements and also change that data in different ways.
according to this article on coupled object interfaces a tightly coupled entity is bad because:
A tightly Coupled Object is an object that needs to know about other objects and are usually highly dependent on each other's interfaces. When we change one object in a tightly coupled application often it requires changes to a number of other objects. There is no problem in a small application we can easily identify the change. But in the case of a large applications these inter-dependencies are not always known by every consumer or other developers or there is many chance of future changes.
This very much is applicable in UI development also. In my opinion this is why not setting state is going to cause you some pain later on.

Returning plain JS object from memoized selector using Immutable.js

I'm working on a React + redux + Immutable.js + reselect application. I'm considering a design where I'm using Immutable.js in the reducers and sagas, but don't want to couple this library with the smart components, so my presentational part of the app as clean as possible.
According to redux documentation your selectors should always return Immutable object.
My idea is to compute derived state in reselect selector and return plain JS object. If I use memoized selector, new object won't be created on every call if underlaying part of redux state is the same, so my component won't be rerendered unless needed.
I know that I'll partially pay with composability, since the selector cannot be uses as an input for other Immutable.js-ready selectors, but I'll get much cleaner smart components.
Are the any other drawbacks of such solution?
Why does redux documentation so strongly encourages to push Immutable object to smart components?
Are the any other drawbacks of such solution?
toJS is an expensive operation, even if memoized. The argument is why toJS if you don't have to?
Why does redux documentation so strongly encourages to push Immutable object to smart components?
The aforementioned, plus it makes reasoning about the whole redux pipeline easier, i.e. any mutations (side effects/morphisms) to state are easier to wrap one's head around as there's a clear flow and point where changes occur.
With all that said, it comes down to preference and where one feels the bottlenecks/trade-offs in one's architecture are. If you feel having a clean separation outweighs the potential risks/caveats with having toJS in the selector, then that's the correct call for your architecture.
On a side note regarding loss of composability in the selector, you could always have two selectors, one that returns the immutable state--used for selector composition, and one that uses the immutable state selector and calls toJS, where appropriate.
Are the any other drawbacks of such solution?
toJS is expensive and also debugging the application becomes more complex.
Why does redux documentation so strongly encourages to push Immutable object to smart components?
Immutable objects are validated more deeper than plain Objects. In case of oldObject === newObject validation plain objects will be compared on a global level whereas oldImmutableObject === newImmutableObject is compared more deeper. This is more efficient on the render tree avoiding unnecessary updates on rendering React components.
Easy to modify objects with helper functions. get, set and more.
Unnecessary data copying is avoided.

Why is two way binding between a parent component and a child component bad?

I've been doing development mostly in AngularJS, recently I was looking into Vue.js and reading its guide, on one page it mentions:
By default, all props form a one-way-down binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This default is meant to prevent child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to reason about.
This is from https://vuejs.org/guide/components.html#Prop-Binding-Types.
I'm wondering if there are any principles of when to use two way binding, and when not to?
For the case where the child component needs to manage an array variable, it seems that two way binding would make sense.
For example, say I want to make my own Vue.js or AngularJS version of http://selectize.github.io/selectize.js/.
If two way binding is used, I would just pass the parent component's array to my Vue.js or AngularJS selectize component, and let the selectize component manage it.
If two way binding is not used, it seems the alternatives would be:
a. Either the parent component would either have to manually update the array when an item is added/deleted
b. Or the parent would have a function that manually sets the array, this function is then passed to the child component
c. The child component dispatches an event which the parent component listens to, and updates its array
I think these are the alternatives? Both seem more verbose and does not appear to provide much benefit.
This is one example, but I think many components would have this issue, another example would be if I have a product-selector component, it would be convenient to just pass in an array variable into this component, and let the component manage the array to reflect the selected products.
My main questions on this are:
Is my idea of the alternatives to two way binding correct?
For the mentioned cases, is there an advantage to using one-way-down binding? (I do not see the alternatives providing much advantage to avoid "accidentally mutating the parent’s state")
If (1) and (2) are correct, what is an example where one-way-down binding, provides a clear advantage to avoid "accidentally mutating the parent’s state"?
"one-way-down binding" is just a principle, similar to OO's Encapsulation, to reduce code complexity.
In my opinion the author didn't mean not to use "two way binding" (actually vuejs support that), just mention you don't abuse it.
In your examples, the product-selector is similar to native input, surely I think you can use two way binding, just like v-model does.

Categories

Resources