Can a component have its own state? - reactjs

Whenever I use Frameworks such as React , Vue or anything else. I see that every value (input value, select value ...) is always being emitted through events to parent. I don't really get why this is good. It takes more ressources / time to pass it to the parent component. Why doesn't the component handle its data by itself?? Why should every single value inside a child component get passed to the state of the parent to make the handling of the data ?
For example, I generally see the loading of the APIs in the parent and then the values of the API get passed down through props or Redux/Vuex. Why can't we get the API values inside the child directly when it's being mounted instead of having to pass it down on many levels or through the local store

It's perfectly valid to have a state inside reusable component, especially if it holds users input. You can still provide it with callbacks in props, which respond to onChange, onBlur or other events based on your needs, or you can communicate with your reusable component via refs, which is fairly flexible way to get user input.
The important thing is, that the reusable component should be as much independent on it's environment as possible. If you don't provide it with a state, the component (in case of your Pickers) will be dependent on props passed down from its parent expressing it's current user input on every rerender and on callbacks updating its current input somewhere higher in component hierarchy on every change, which is not what you want in every case, and it already forces you to make relatively large adjustments in you parent component, which misses the point of reusability.

Related

How to pass data from grandchild to parent component in React?

I have a form (Parent) which contains an input field (Child), which gets its value from a reference table (Grand-grand-child) that is displayed as a modal (Grand-child) which opens up by clicking a button attached to the input field. This is a nested structure that roughly looks like this:
I need to set the value of the input field by selecting a row in the reference table and confirming my choice with a button "SET VALUE", which means I need to pass data three levels up from Grand-grand-child to Parent through Grand-child and Child.
My state is kept in the Parent component. Is there a simple way of achieving that without using external libraries? Please offer a solution using Hooks as all of my components are functional components.
Here is the code: https://codesandbox.io/s/festive-fast-jckfl
See CreateRate component where:
CreateRate.jsx is the Parent
InputField.jsx is the Child
DataFetchModal.jsx is the Grand-child
Airports.jsx is the Grand-grand-child
Pass a change handler function from parent (where state lives) down to the grand child. The grand child should call this change handler when clicking the Set Value button.
If this is too much prop drilling
look into component composition first
if that doesn’t work out, look into context api
Update:
You mentioned your problem was trying to access the state inside Grand-grand-child from your Grand-child. In this case you can lift the state up (to Grand-child). This means lifting 'airports' up to DataFetchModal. Here is more info on lifting state.
https://reactjs.org/docs/lifting-state-up.html#lifting-state-up
Also, it appears you are running into these problems because your code is very nested and not very composable. I would suggest looking into how you could better break up your components. One way to accomplish this is using compound components.
https://kentcdodds.com/blog/compound-components-with-react-hooks
Determining how to break this up better would take some time. However, just looking at this briefly. You may be able to move your DataFetchModal to your parent. Pass a callback to the InputField to fire it off and send the identifying parameters (what input called it). Then, from the parent, compose in whatever modal body using composition. It appears you have a lookup object (objType) inside DataFetchModal. Maybe this could go away by using composition (not sure, and probably separate topic).
Update 2:
I pulled down your code sandbox and made a few changes that may help access parent level state. I moved the modal into the parent. Check it out.
https://github.com/nathanielhall/Test

How to reset state of a child reactjs component

I have a react.js app which loads data from an API displays a bunch of questions (textboxes, radiolist, checkboxes, etc). The user fills them in and submits all answers back to the API, which then send a new set of questions.
All these questions are in a single object, so I've created parent react.js component which holds the current set of questions in state. When the state changes it re-renders each question below. This works pretty much fine.
The problem is that sometimes the API displays the exact same question for twice in a row, but as this is held in state and react.js is clever enough to know it doesn't need to render a completely new component, because the old one will do (with a few small updates).
The problem is that if I select a radio button on the first one, based on the initial data stored in state of the child component, which was initially set within componentDidMount). But when the second question comes along, because its essentially the same component, the state remains. The constructor is not called again.
I think I should be using one of the other events, perhaps:
componentWillReceiveProps
componentWillMount
componentWillUpdate
but I can't figure out which one is the most consistent one.
I basically want to reset the selectedAnswer everytime the parent has received new data from the API and essentially re-render all child components (but react won't do that).
Edit
I wonder instead of trying to reset this via the internal lifecycle events, whether I can pass in a different set of props into the component, so it can decide whether to re-create or re-render in the usual way.
okay so to optimally do this lets suppose you api which returns the set of questions, it might contain some id associated with it. Using that id create a uniq key for every child component while rendering something like below
<Child key={`${data_id}_${index}`} />
This will ensure that for the same set they do not keep mounting again and again and will only mount if a new data set is fetched in which case data_id will change which would cause remounting of each and every child component
I'd encourage you to check out Redux. It makes managing state much easier. I'd contribute some code on here but I am not sure I actually understand the question. If you linked us to your Github, then I could probably answer this specific question.
Also, it seems like you don't really need to touch state. It sounds more life attaching an event and controlling state that way. For example, using onSubmit, you can make an API call (and whatever else) and then have another function to reset the form state afterwards. It would be pretty straight forward, especially if you are using then/catch Promises.

React: best way to handle re-render of unrelated components

maybe this is very basic, but I'm still new to react:
I want to have different types of components - with (possibly) no relation to each other - that re-render on changing one specific value in my application. I tried the Provider store of mobx, but of course I received warnings, that you should not change the value of stores.
So for example
<RootElem>
<SimpleComp1>
.....
<ReRenderMeOnRootElemStateChange1 />
.....
</SimpleComp1>
<SimpleComp2>
.....
<ReRenderMeOnRootElemStateChange2 />
.....
</SimpleComp2>
</RootElem>
and the re-rendered components should have acces to the new value/state of the RootElem, so that they can change based on this new value.
What is the best way to do that? Where should I store my observable value for the re-render, and how can I make components listen to it, even if they are no children of the state changing component? I dont' want to pass the props all the way down to every single component, that should re-render on changing the observable value :)
Furthermore I'm wondering if you can make a component listen to another one's changes, even if they have no relationship to the each other in the component tree (except the application's root component).
Thanks!
React components re-render automatically by default when they receive new props. So if you simply pass values from <RootElem> down your component tree via props, everything should work as intended and the sub-components will re-render with the new value.
You can control whether or not a specific component should re-render by using its shouldComponentUpdate hook. I'd say that most of the time you won't need this unless you're trying to make a specific performance optimization.
You can also pass new values to the sub-components using context, though this approach is generally discouraged unless you have some very specific use cases for it and know what you're doing.

In reactjs, are props pass by value or pass by reference?

As far as I can tell, if I pass a parent component state down to a child, then that child gets the live state of the parent.
So a change made in the state of the parent is immediately also available in the child via the prop that it came on.
Is this correct?
It's basically the same mechanism as anywhere else in the language, as you'd expect. Primitives are passed by value and variables that aren't primitives will be passed by reference.
React takes care internally of the updating of props, so that children always have the most up-to-date value of the prop.
This is the lifecycle method that is called when receiving new values for props.
However, make sure you respect the infrastructure put in place and the exposed API that React gives you.
Short answer: props are passed by reference.
The reason it can be confusing: if you change the parent's state by hand (bad practice!), the object will change in the child component, too. But won't trigger re-render! (The child component won't "know" that its props has changed.) So you won't see the UI change.
However if you change the parent's state with setState (the preferred practice), the child will be notified, that it must re-render itself.
If you pass down the state of the component as props to its child, then if the state of the parent component changes it re-renders, which will also re-render its children with the refreshed properties. The children don't directly listen for the state change like the parent does, they are simply re-rendered as as result of its parents state change and updated.
Take a look at this - https://facebook.github.io/react/docs/multiple-components.html. It will help you get your head round how this concept works. Hope this helps!
When the state of a component is changed, then the component is re-rendered by React. While doing that , its child components are also re-rendered, which causes changes in them also.
No, they will not be duplicated, you will access to those props by reference, because they come from a single object wich defines them, and then pass them as a reference to the child objects.
You can take a look to the official documentation here: https://reactjs.org/docs/react-component.html.
I suggest to use a stateless mechanism to handle large data, expecially if shared.
Personally I use mobx (https://github.com/mobxjs/mobx) wich is a great framework to create stateless apps.
With this method you can handle data and state updates in a single component, called Store, and use components to render html only, and not to handle data, wich is a great boost on application performances.

Transfer props to children without re-rendering parent

Is there a React-okay way to pass new props to children without re-rendering the parent? Nothing in the parent component is changing except that new props are being passed to that component which are being passed through to its children. I thought context might be appropriate in this situation but it seems like the documentation states otherwise.
It depends what you mean by React-okay. You can in fact use contexts for this, but I don't recommend it. It's much easier to reason about and debug props flowing down directly through your view hierarchy, and if the parent isn't changing at all the render function should be quite cheap to execute.
If it isn't cheap, you may want to rethink how you're structuring your components. For example, you may want to split off the expensive part into a separate component that only gets rendered when relevant props have actually changed, or at least secure the expensive functionality behind a conditional props check.

Resources