Component to edit part of parent's state - reactjs

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.

Related

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.

React: Passing the parent into a child

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

Can you handle state in this example without Redux or Flux, and if so how would you go about doing it?

Suppose I have a timer structured so that you can view and time multiple projects at once, and within each project you can view and time multiple tasks. Since this is a timer, you can only time one task at a time, and therefore one project at a time.
Because of these restrictions, I've separated the timer into three separate structures:
TimerContainer (outer, holds and displays all project objects)
ProjectContainer (middle level, holds only one project, with all tasks associated with the project)
TaskContainer (inner level, holds only one task).
Only the TimerContainer and ProjectContainer hold state.
TimerContainer:
The TimerContainer doesn't know anything about the tasks, but it does the initial API call to seed all projects and tasks with starting values.
The TimerContainer is also concerned with which project is currently tracking time (i.e. holds a projectID value for whichever project is currently timing).
ProjectContainer:
Each ProjectContainer holds information about which task is currently timing (if any), and updates (both here and via an API call) the time spent on each task after they've completed timing.
At that time it informs the TimerContainer it (that project) is no longer timing.
As props the TimerContainer is giving ProjectContainer the currently tracking project ID, list of tasks and their seed values, and various project information.
Here is my question:
If I update the TimerContainer's "Currently Tracking ProjectID" value, it will trigger a re-rendering of all the ProjectContainers, including the one that just updated one of its tasks' times. That, in my mind, seems to revert it back to the original seed value of that task unless I update the (now static) seed information held in the TimerContainer for that specific task.
If I do that, it makes me think that I have to set the state for both the seed information and the currently tracking projectID with the same call, because if I do it sequentially I'm not sure if it will get to the second state change request.
If this is indeed a problem (and please feel free to say otherwise), I imagine it could be alleviated by Redux or Flux, but given an already established architecture I would like to see if there are clean ways of handling this without bringing in another library first.
Bottom line, how is this solved cleanly without another library?
Update:
It seems as if I was confused about the way re-rendering affected state initialization (namely, it doesn't). I modified Adam's example below to prove that to myself
(link here )
After that realization, the solution to my problem simply becomes writing up a function that would handle "Currently Tracking ProjectID" prop value change on each of the ProjectContainers.
Another thing to implement is the shouldComponentUpdate function (thanks again) by checking if the ProjectID was related to that ProjectContainer.
A component re-rendering shouldn't cause that component to lose it's internal state. Here's an example: the child component re-renders because the parent changes state and passes the child new props, but the child keeps its own internal state.
As far as design options in general, there are a bunch. Here are a few I'd consider:
Re-rendering is a performance hit, so consider customizing the shouldComponentUpdate function for child components to keep them from rerendering
Try to make as many child components stateless or pure as possible
Consider not persisting the "seed" values in the parent component - not sure if there's value to knowing the initial value, but if you just pass that down to the child components, they can store and increment that
On the whole though, it sounds like you might benefit from a store. Being able to separate out organization of state from functionality can be helpful.

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.

Correct way to update owner state

I have two components, contact form, and input.
At this moment i pass onChangeEvent from contact to input as is described in many tutorials and its works fine - input update his owner state.
But there is way to pass 'this' from contact to input by prop, or context and then I can update owner state without passing onChangeEvent - but is this a good idea?
Is there another option to update owner state without passing onChangeEvent?
I believe you could technically do it, as a React component is a regular javascript object in the end, so you could pass it as a prop.
However, that's not a good idea in general, for various reasons:
It tightly couples the two components together. If you ever want to reuse the input component in another place, you'll need to pass in the exact same state.
Linked to this, it allows manipulation of the internal state of one component, by another component, which is a violation of good OO design.
You are right however, that things tend to become quite verbose when working like this. They also become hard to reason about when one has more complex trees of components passing props and change handlers between them.
One solution to the problem, is employing the Flux design pattern, and namely it's Redux implementation.
In Redux one has a single piece of global state, a plain object, of which components see pieces (sub objects). Components receive this state as props, and just render from it in a simple fashion. There's a set of actions which transform this state, and any component can issue such an action, as a result of user interaction. There's still the concept of "state", but it is reserved for truly local things, such as the state of a form before pressing the save button etc.

Resources