React: Passing the parent into a child - reactjs

I am working on a React app, and I need to modify the parent's state from a child component. Of course, I could simply write a function in the parent, and pass it as a prop to the child (like everyone else seems to be doing). However, I tried instead to pass the entire parent as a prop to the child, so that the child can freely modify the parent's state.
This is how my parent looks with its children:
{this.state.entries.map(entry => (
<UserEntry
...
mainThis={this}
/>
))}
Notice how I pass the entire parent into the child as a prop with a this. From my child code, I can then modify the parent's state with a simple this.props.mainThis.setState().
Of course, this worked, and I am really pleased with myself. However, I am wondering why people are not doing this. Would it affect performance in the long run, or something?

As your codebase grows bigger and more complex, you will find yourself trying to find a way to manage the complexity. It is important for reducing bugs and adding new features. Doing this opens up a can of worms.
Heres an example. You do this in one parent to child. The child also has a list of elements that it passes the this reference to. Finding out which child element is updating the state that causes a bug from data becomes a chore. You won't have a good place to drop a debug point to see values, and the job will be harder
A big advantage of React is the idea of a component. React makes the component re-usable and self contained. If you start passing the this reference, your parent component becomes tightly coupled to the child component. It becomes harder to tease apart the functions of each component.
Feel free to experiment with this pattern. When the codebase reaches the tipping point, you will feel the pain of this design choice very quickly.

I am wondering why people are not doing this. Would it affect
performance in the long run, or something?
It will make your code hard to debug, understand and test because of tight coupling between parent and child. This is also against encapsulation principles because a child component shouldn't know anything about state and internal implementation of parent component and vise-versa. Components should be loosely coupled.
This has nothing to do with code performance but it will surely affect performance of you team in the long run.
Bonus Read: 7 architectural attributes of a reliable react component

Related

Does useContext/useSelector affect performance, compared with passing through attributes?

I have a component which contains several nested child components; these children require information about the parent component, as well as data from my redux store. Given their quantity, is it better performance wise to use the useSelector hook once within the parent component and pass it down through attributes (rather than context), than it is to have each child use useSelector? Additionally, is it better to pass information about the parent component through its attributes, than it is to have each child use useContext?
edit: in testing, there is a 20% increase in speed when passing through attributes; my guess is useSelector/useContext is more costly in its declaration than an attribute? Can anyone confirm this to be true?
is it better performance wise to use the useSelector hook once within
the parent component and pass it down through attributes (rather than
context), than it is to have each child use useSelector?
The second one is a better choice. You will have less unnecessary re-renders compare to the first choice.
In your first choice scenario, when something in the parent is changed, it will trigger the re-render for the component (means, the children will be affected).
is it better to pass information about the parent component through
its attributes, than it is to have each child use useContext?
The answer is same with the above.
As you can see react-redux uses context API
https://github.com/reduxjs/react-redux/search?q=useContext&unscoped_q=useContext
In terms of performance, all the above approaches are close to each over.
The best way to deal with performance issues is the following:
Wite good-quality code (number of args per function, number of lines per module, cyclomatic complexity, block nesting, fan-in/fan-out coefficients and so far and so on). Do not take into account performance issues.
Profile and find out bottlenecks in your good quality code. Prioritize them.
Fix found issues https://en.reactjs.org/docs/optimizing-performance.html

From OOP to ReactJs: Why I should remove the local State from a Component and move it to their Parent?

I would say that I have good experience with a lot of OOP languages. Most with Java. I've made full stack development with Spring boot and now i'm trying to learn React.
My point with all this is that maybe I'm to used to OOP languages so there are some "design philosophies" that I cannot understand.
I've started with this tutorial video:
https://www.youtube.com/watch?v=Ke90Tje7VS0
It's pretty great and clear but I have an issue in one part in particular:
1:47:55 Removing the Local State
To summarize the video, he makes an component called Counters that contains N componentes called Counter. This component Counter is just one number and a button that every time is pressed the value should increments by 1.
Originally, this value was stored as an state in the Counter component. This makes sense thinking in a OOP way. But then, in that chapter from the video he suggested to remove that state and mantain that value in the parent component, Counters.
And every time the button "INCREASE" is pressed, what is doing is calling Increment in the parent component. The value is stored in Counters. Not Counter.
Now, my question: Why not keep the VALUE state in the Counter component, and everytime is increased, inform the parent component that this happened?
How is this design philophy called? Any tutorial/book/video that explain this better for the people that comes from a OOP background?
Sorry is this is a dumb question. Thanks!
The goal of this is to have a "single source of truth". In other words, if this piece of state is only kept in one place, then it's impossible to have a conflict between different versions, because different versions don't exist. And this in turn means you don't have to devote any effort or code to trying to keep states in sync with eachother.
Now in principle you might think of having the child component be that single source of truth. But the way react is designed, props always flow from the top of the component tree to the bottom. A parent component passes props to a child component, not vice versa, so react makes it very convenient for the state to exist in the parent component and then be passed to a child.
As you mentioned, the child could notify the parent of changes, which would be done through a function prop. But in order for the parent to rerender and use this new data, it will then need to set state on itself (setState causes render). And now the state is being kept in two places, which is the thing we were trying to avoid.
The design philosophy is known as smart vs dumb components and it becomes more useful when dealing with larger state management libraries like Redux. The goal is to separate your logical components, those that deal with manipulating the state, interacting with other libraries like Redux etc. From view components. That way your view gets to be a pure function, reacting only to the parameters passed explicitly to it. This makes them extremely easy to test. And you only have to test that your smart components are passing the correct values to the view only components. Decoupling in this way makes testing smoother and prevents a variety of bugs that could otherwise be difficult to track down.

How to prevent component re-render (update) inside animations with REACT

These past few days, i've been playing around with different animation libraries for React, in an effort to find a solution for transitioning between views (not routes), where a view would be a component wrapping other components and so on.
so far i tried:
react-transtition-group
react-animations
react-spring
Still need to experiment with react-motion's Transition...
...and there are a lot more out there, but all these, do what i need, except for one thing... while each state of the transition/style is applied, the child component(s) always update, triggering a re-render (which makes sense by the way), unless the child's shouldComponentUpdate() returns false, or is wrapped inside a PureComponent, both of which are not a solution, since you might (surely) want to do "things" with your component after the transition ends.
All the examples out there, serve their purpose, but they all use either functional components, or simple strings, for demo purposes, none of which one should care if are re-rendered or not, but a simple modification that would log every time the component is rendered, will show that they render multiple times during the transition.
Oddly enough, nobody seems to care, or is unaware. I have found very few questions or issues regarding this matter, though it's very much real, and the libs are very poorly documented on this.
Please share your solutions for avoiding this issue.
My workaround is to wrap the transitioned children/views inside a simple PureComponent, to prevent them from re-rendering, still it doesn't seem right.

Component to edit part of parent's state

Ok I am studying React.JS now. Consider the following situation. There is a root component holding the model as state. One of its children is a complex control responsible for editing part of the model. There are some rules: some user's actions modify the part in one way (to be specific, sets a list to contain exactly one clicked item), other actions modify it in other way (like, simply add that item to the list). Those rules, of course, are not imposed by business logics, it's just the way I designed the particular child component. Now I have to decide how to connect the child's UI elements to the model and vice versa.
1) I can make the child stateless. Make it accept the current model state as props, render its UI according to that props, and upon click, send the parent an event (via some callback in props) "hey I've been clicked this way". The parent can examine the event and either apply setState(model=>replace_list_single_entry(model,event.id)), or setState(model=>add_entry_to_list(model,event.id)).
Drawback: the parent has to know much about logic specific to a component implementation, while actually I should be able to switch to another component with another implementation. So much for encapsulation, component-driven design, and low coupling.
2) I could make the component calculate a new state for parent (at least in some form, maybe not exactly one which is in the model), send it to some props.onChange, and then the parent could simply setState to accomodate this calculated state.
The severe drawback as I see it is, since setState is asynchronous and can be batched, an event loss might occur. Look, the child interprets the user's actions as "add ID1 to list", takes its props.list, makes another list of it and of the ID1, and sends that list to a parent, which makes setState; while that setState is still pending, the user makes another click to add yet another ID2, but the child's props.list is still the same, so the child sends the parent a new calculated list containing ID2 but not ID1. The parent calls setState with this new list and voila, eventually ID1 is lost from the list.
3) I could send the parent not the state calculated from my props, but state calculator. The parent applies this calculator to some "props" object, which it populates from the current state in the same way as if to pass to children's props. (I mean, this may be simply some property from the model, but may be something pre-processed) The resulting "props" are then re-integrated into the model.
Drawback: it looks overcomplexified. But maybe that's the way to go, actually.
4) I could make the component stateful, have its own state describing its UI controls, and after each set state completion, send the updated state to the parent. This however is no different from approach (2) in sense of drawbacks, and adds some more concerns - admittedly, quite solveable, - like, keeping internal state eventually-consistent with parent's state.
So, what is the proper way to do the trick?
It really does not make any sense to me.
I mean, the pattern "<Child onChange="{event=>this.setState(event.data)}>"> (or something similar) is SO common, everyone rushes to suggest it when some newbie asks "how do I affect parent's state in a child?". But it's enigmatic how everyone is silent when I say "this approach has major drawbacks, how do I avoid them?" How do they people write their code, then?
OK the only solution, given that no one experienced user could give me an exhaustive answer, seems to be "don't make a parent's state dependent on children, make components only responsible for non-overlapping sections of the model, instead of mapping children to a subsection of what's already mapped to a parent".
Even despite such an approach is actually not a decomposition.

Are there any disadvantages to just passing the entire state to components from redux?

I'm using the ES6(?) decorators with Redux and React. In many examples I see people explicitly assiging which store items get passed as props. In some examples I see people using spread attributes to just pass everything through like:
#connect((store) => {
return {
...store
}
})
export default class SomeComponent extends React.Component {
...
Is it okay to just do this for every component, or should you cherry pick the props specific for that component?
There is a huge performance detriment, as on every action dispatch react-redux runs every connected component's mapStateToProps, and then shallowly compares the old props to the new props. If there's any change the wrapped component will re-render. Basically if you pass in the entire store, every connected component will re-render on every action dispatched.
Yes, there are. It's not as easy to read what props the component is actually using. Also, props that you aren't using in the component can change and will trigger unnecessary re-renders.
I went thru both paradigms of redux development.
Every component gets all the actions, and all of the state.
Only the container/parent/base pages get all the actions/state
Gives the children only what it needs
What I found. Yes, there is a performance hit because if every component has every state property, imagine you change one state value - every single component gets that update - whether it needs it or not. Constant updates.
All night you are woken up:
Imagine your dog wakes up at 3:30am every night to go outside to pee.
Imagine your neighbor wakes up at 4am for work.
Imagine your other neighbor wakes up at 4:30 am for work.
Imagine your family wakes up at 5:15 am for work.
And you need to get up at 6:00am work.
In all of those scenarios, you are woken up. Over time, how effective are you gonna be at work? You are gonna be tired, sluggish etc...
Now, imagine - you CAN only ask to be woken up, when you need to be? And not all those other times, that have nothing to do with you?
That is how I think of it. So, let your child components only know about the things they care about.
So, I usually have the container page/parent - know about everything - and hand down what it needs.
Caveat - I have found, there are some cases in which a child component (for whatever reason) needs to know about nearly everything. For me, passing every single thing down to multiple levels - also impacts those children you pass along the way...
parent --->
child (just care about one thing) --->
child (just care about one thing)--->
child (I want alot of stuff)
I don't like to pass all that stuff down all those children, especially if those children higher up the ladder don't care. So, in that deepest most child, I give it everything from the get go - and not pass anything to it.
That is a little bit of a performance hit, I'll take to make the code cleaner.
But overall, don't give every component everything. Makes a huge performance difference overtime, and as your application grows.

Resources