I have many small React editor components that receive a document prop. I dont want them to be reused so I add a key to them:
<Editor key={doc1.id} doc={doc1}/>
I would love to derive the key automatically from the doc.id inside of the component class. Is this possible?
My aim is that I have a much cleaner:
<Editor doc={doc1}/>
Keys are a special mechanism used to invalidate indentity of components (the docs explicitly mention the identity issue keys are solving) : if a react element in a react tree only differs with its key between two render passes its underlying component will be unmounted and remounted. Keys are mainly used when rendering a list, or to force unmount/mount for a specific component. So the answer to your question is no
React already tries to reuse a lot of the dom state if nothing changes and there are lyfecycle methods available to prevent unwanted rerenders: shouldComponentUpdate. However, as the docs state using this lifecycle should be considered performance optimization and will in the future considered as hint rather than as a directive. Unless there is a specific perf issue this could be premature optimization IMO.
Related
Let's say that I'm fetching some images from an API in the App component.
Then I want to pass it to the component responsible to rendering images. But this component is not a direct child to the App component. It is the child of a direct child of App component.
Here's how I would pass the images array down to the image component, but I feel like it might not be the best approach.
But what would happen if this hierarchy gets more complex - even just by one more component:
Intuitively, it might not be the best thing.
So, what would be the best way to pass the images array down to the image component, if there are many other children between them?
The problem is usually called Prop Drilling in the React world: https://kentcdodds.com/blog/prop-drilling
A few options:
Passing props may not be that bad. If the app is small, is a very modular -and easy to unit test- option . You can reduce the verbosity by using prop spread: <Comp {...props} /> and by keeping your component interfaces similar. (many people dislike prop spreading as you can unintentionally pass unsupported props, but if you use TypeScript the compiler will catch that).
You can use a React Context: https://reactjs.org/docs/context.html (as other mention in the comments). However, keep an eye on how your context objects are defined (keep them small). React will re-render all the childs using the context when the value changes, is not smart enough to automatically detect changes at the property level. Frameworks like Redux or Zustand use other mechanisms to allow a granular control of the shared state (you'll see examples of a useSelector hook).
You can also take a look to a state management framework (Zustand is my favorite, but Redux is more popular). However, it may be an overkill for small things.
My personal choice is to start with prop drilling, it's easier to modularize and unit test. Then you can think on your app in layers: upper layers depend on a context (or a state framework), and lower layers receive properties. That helps when you want to refactor and move reusable components to other projects.
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.
React discusses on this page about performance that you can use shallow equality and avoid mutating objects, so that components need only to check references to see if props or state changed.
I'm actually wondering about the opposite: is it possible to have the equality check use deep equality and ignore when the object references change (as long as their contents don't change)?
Reason is, I have a library which returns a cloned version of some internal variables, and to see updates on those variables, I need to re-ask for that internal variable, thus getting a fresh new clone. So I'll get entirely different objects by reference, but they could have not changed any of their fields. But every time I request such an update, React thinks everything has changed because all the references changed, and it re-renders a lot of unnecessary stuff.
Current solution: threw this in a component to stop it from rendering as long as the objects' fields don't change
shouldComponentUpdate(nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
which does the trick since lodash's isEqual equality check is deep, but I'd have to do that on each component that wants this behavior. I wonder if there's either a
preferred way of achieving this
an anti-pattern I'm using which leads to this in the first place and I could avoid it entirely
or maybe the above method is best.
I would not suggest you do this for the following reasons:
Deep comparisons are costly. So everytime something changes you will have to do a deep comparison and then do the rendering part. We would just be better off letting react do the rendering cause it was made for it.
As for the case of handling it in all the components. We can avoid this problem by destructuring the object thus sending smaller props, now the react can handle the optimised re-renders. eg:
<Footer data={object} />
<Footer title={object.title} copyright={object.copyright}/>
I hope that helps!
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
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.