Updating parent component without a call back function in react js - reactjs

I was doing a POC coding on React js with component which has a Child component.As far as I know, there was no other way to update the state of parent from child except through a call back function from the child to the parent component. In my case, I tried to pass the state of the parent to the child and set them on the child state directly as props (this.props.).I noticed that if I change the state of the child, the state of the parent is also getting updated. I'm bit confused. Could somebody please help ?
Here is my code.
index.js
ReactDOM.render(<App2/>,document.getElementById('root'));
App2.js - Parent component
import React from 'react'
import ScreenTest From './ScreenTest'
class App2 extends React.Component{
state={
address : {
houseName:'1234 House Name'
}
}
render(){
return(
<ScreenTest parentState={this.state} address={this.state.address} />
)
}
}
ScreenTest.jsx - Child Component
import React from 'react';
class ScreenTest extends React.Component{
state={
parentState: this.props.parentState,
address : this.props.address
}
clickButton = () =>{
let addressTemp = this.state.address;
addressTemp.city= "Kerala";
this.setState({
address:addressTemp
})
}
render(){
console.log("To view the state when the screen renders",this.state)
return(
<a onClick={this.clickButton}>Click me to update the state and re render </a>
)
}
}
Code explanation:
I am invoking App2 component which has a child Component ScreenTest. I pass the currentState of App2 to ScreenTest. In ScreenTest i set the state from the values passed as props. In ScreenTest I have an anchor tag when clicked, updates the "address" state of ScreenTest and re render Screen. When the screen is re rendered , i check the state to see that parentState is also getting updated with new Address (i.e city is added to it).
Please tell me how the parentState is also getting affected by it. I'm bit confused.

You must note that when docs say that in order to update parent state from child, you must make use of callback and let the parent update its state, its the ideal and the correct way of doing it
In your code you are accidently updating the parent state you mutate the state by calling
let addressTemp = this.state.address;
addressTemp.city= "Kerala";
In Javascript, object are used by reference and updating a property in object directly will update it for anyone using that reference
So when you assign props to state in constructor like below
state={
parentState: this.props.parentState,
address : this.props.address
}
The state properties hold the reference of props object and hence the props also get updated when you mutate the state property by updating addressTemp state
The ideal way to update state is to clone it and then make changes so that you avoid unexpected issues
clickButton = () =>{
let addressTemp = {...this.state.address}; // clone state
addressTemp.city= "Kerala";
this.setState({
address:addressTemp
})
}

Related

Getting Component State

Lets say I have component named Vault
class Vault Component{
State : { animal: dog,color:blue}
}
Lets say I have button in component named App with a button
class App Component{
State: { animal:null,color:null}
}
<div onCLick = {goGetVaultData()} className="button">Press Me</div>
Question is how does goGetVaultData function look to extract state from a diffrent component
goGetVaultData(){
// what do I look like ?
}
If you want data from a parent component, have the parent pass it down as a prop, then access it using this.props.
If you want data from a child component, pass a function as a prop to the child. The child calls that function, and when they do you call this.setState to save the value, and access it later using this.state
If you want data from a sibling component, move the state up to whatever component is the common ancestor of the two components. That common ancestor passes props down to both components.

If React props are readonly, how they can change (whats the usage of getDerivedStateFromProps)?

I'm learning React. I learned that props in react are readonly.
But i read somewhere:
getDerivedStateFromProps updates the state based on prop changes
So i got confused. If props are readonly, how they can change?
They are readonly in the context of a component, meaning, you can't assign a new value to them.
But a parent that passes props to child, can pass different props based on some condition. In that case, the child get rendered with a different props.
Example:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 0,
};
}
render() {
return (
<div>
<Child prop1={this.state.value} />
<button onClick={() => this.setState({ value: this.state.value + 1 })}>Click me</button>
</div>
);
}
}
In my example, each click on the parent's button will change it state, therefore, React will re-render it, and then this parent will pass a new value to Child component.
I think you need to understand component life-cycle and how to use and handle props which is described beautifully in below links:
https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
https://reactjs.org/docs/components-and-props.html#props-are-read-only
Props are read only means you can't change the value, but it doesn't mean you can't update it, for that you need to pass updated props back to child component and go any lifecycle methods to it.
An update can be caused by changes to props or state.
when there is update render() method is get called.
you are saying update to props, which directly means you are changing and modifying child,
props changed means, the data passed from parent is changed which leads in changing props,
always remember state passed from parent is considered as props for child is key point.
static getDerivedStateFromProps(props, state) gets called right after render() used rarely mailnly for animations transitions purposes.
the things possible with componentWillRecieveProps() and componentDidUpdate() is now done by getDerivedStateFromProps(), it will return object in response to change in props, and null if no change, sounds wonderful.
as you can see method is static you cant change any data, you can just play with your nextProps and prevState only.
this is useful for components having async api calls.

Why parent Component can change Input.value with setState?Doesn`t input have it`s own state?

As we know,parent Component can not change child Component state,because state is independent and private! And the Official documents also said "In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input",then why we can use this.setState({value:this.value+1}) in parent Component to change ???I was confused about this!
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 100};
setTimeout(
() => {
this.setState({value:(this.state.value+1)});
},
1000
);
}
render() {
return (
<inpt value={this.state.value} />
//value will change from 100 to 101
//if here is a user-defined component,we must use
//componentWillReceiveProps(nextProps){this.setState({value:nextProps.value})}
// to update child component,but the DOM component doesn`t need!why??
//Does DOM component hasn`t it`s own state?
);
}
}
from the same page, you get the quote, react mentions that the form inputs are a Controlled Components, which means that the parent component of them can affect there state and it can know some information of their current state, as the onChange listener on the input, the parent component will know when the input is changed and what its new state for the value.
the opposite of this is the uncontrolled components which is a component that the parent may not know anything about its current state, as the image slider in a page, the page doesn't know what is the images that the slider renders, and it doesn't know which image is active now, until you add a handler like onImageChange, which will tell the page which image is the active now, and by that you turned it from uncontrolled component to a controlled component.
Recap:
the controlled component: a component that changes its own state, based on parent component props values, and can share some of its state information with the parent component by the callbacks that the parent passes to it as props.
the uncontrolled component: a component that doesn't change its own state, based on the props that passed to it from the parent, and doesn't share pieces of its state with the parent by the callbacks that the parent passes to it as props.
I hope that answered your question.

What is the proper way to handle React state and props

I've been using React for a while, and I've tried many different approaches to do this, they all have their advantages and disadvantages so I'd like to clarify which one is the way to go.
So I have this example scenario:
- A (smart) parent component, listening to a flux store
- A (dumb?) child component being rendered by the parent component above only rendering a view and having some "small internal logic", and by that I mean, some logic that doesn't make sense to be handled by an external action, like onChange events that update its input value, for example.
Should I only pass whatever I wanna pass to the child component as props, and don't mess with its state. So whatever small logic I need to do I update its props directly (even tho I know it's not recommended to update props directly)?
Or
I pass whatever props I wanna pass to the child component and then "get them" in the getInitialState, do that small logic using its now state variables?
The problem with the second approach is that when I actually send an action from the child component, and the parent component listens to the stores results and gets updated, and I have a hard time re rendering the child component now, unless I change its key value, which I also think it shouldn't be done this way.
And the first approach, even tho I'm changing props, which, like I said, I don't think it's also the best thing to do this, I don't have a problem re rendering the child component after sending an action that updates the store that the parent component is listening to.
Probably there are other ways to do it, and for sure a better way. And that is what I'd like to see. Let me know if the question is confusing and I'll try explaining in some other way.
Thanks!
You should only set state from the main (parent) component. All children components should be "dumb" components. If you need to manipulate state from a child component...have a function in the parent component that modifies the state needed...then pass that function as a prop to the child. When the action needed to update the state in the child is completed, call the function passed in as a prop which will call it in the parent component and will update state accordingly.
Below is just some boilerplate code to give you an idea as to what I'm talking about.
Example child component:
import React, {Component} from 'react';
class Child extends Component {
edit = () => {
var state = "string";
this.props.edit(state);
}
handleChange = (evt) => {
this.props.inputChange(evt.target.value);
render() {
return (
<button type="button" onClick={this.props.edit}>Click Me!</button>
<input type="text" name="name" onChange={this.handleChange}>
)
}
}
export default Child;
Example parent component :
import React, {Component} from 'react';
import Child from './Child';
class Parent extends Component {
edit = (val) => {
this.setState({data: val})
}
inputChange = (val) => {
this.setState ({input: val});
}
render() {
return (
<Child edit={this.edit} inputChange={this.inputChange}>
)
}
}
export default Parent;

Getting a child's default props to set the state in the parent in ReactJS

Similar to Pass props to parent component in React.js but I am only interested in getting the child component's default props into the parent.
So why would I need to do that?
Well, I have a parent component that renders a child component containing an HTML form. The parent's render() method passes its state data down to the child as props, as it should.
Initially, the child form should contain some default data only. And it makes sense for that data to be taken from the defaultProps defined in the child component. After all, I don't want to be setting up a load of default data in the parent's state for the sole purpose of passing it down to the child as default props. The parent should not need to define the child's default props. The child should know what its own default props are.
So in my initial parent render(), I leave my state as undefined. When this gets passed down to the child as undefined props, the child will use its defaultProps instead. This is just what I want.
Time passes...
Now the user changes a field on a child component's form. I pass that change back up the parent via a callback function for it to recalculates the parent's new state. I then call a setState() in the parent to re-render all the child components as normal.
The problem is that I need my parent's state to be an object, containing further nested objects, and am using the [React Immutability Helpers][1] to calculate the new state in the parent, like so:
handleFormFieldChange(e) {
// reactUpdate imported from 'react-addons-update'
var newState = reactUpdate(this.state, {
formData: {values: {formFieldValues: {[e.currentTarget.name]: {$set: e.currentTarget.value}}}}
});
this.setState(newState);
}
The first time this code runs, it will throw an error because it's attempting to update the state values and there is no state to update. (I left it undefined, remember!)
If I attempt to get around this by setting up a default initial state to an empty object (each with nested empty objects) I run into a catch-22. On the first render, these empty values will get passed down the child as empty props, so overriding the defaultProps that I set up for the child component. Bummer!
So as far as I can see, I need a sensible initial state to pass down to the child component, but without (re)defining the whole thing again in the parent. So in this case, I think it would make sense to pull the child's defaultProps into the parent, just in order to set the parent's initial state.
I have a way of doing this, which I will post later on. But before I do that, does anybody have a better way of doing this? One that would avoid having to pass the defaultProps from the child to the parent at all?
If you're using React.Component then defaultProps is a static object on the class so it's easy to get.
export default class Child extends React.Component {
static defaultProps = { ... }
}
// If you don't have es7 static support you can add it after the class def:
Child.defaultProps = { ... }
The parent just needs to do:
Child.defaultProps
to access it.
As threatened in the original post, here's how I'm getting the child's default props sent up to the parent.
I'm using ES6 Classes and the module pattern, with Webpack and Babel to handle the building and transpiling.
So I have two files, let's call them Parent.jsx and ChildForm.jsx. Here's how ChildForm.jsx might look (NB: not working code!):
class ChildForm extends React.Component {
render() {
var fieldValues= this.props.formData.formFieldValues;
return(
<form>
Field 1: <input type="text"
name="field1"
value={fieldValues.field1}
onChange={this.props.handleFieldChange} />
</form>
);
}
}
export function getDefaultProps() {
return {
formData: {
formFieldValues: {
field1: "Apples",
field2: "Bananas"
}
}
};
}
ChildForm.defaultProps = getDefaultProps();
export default ChildForm;
The trick is to move the setting of defaultProps to a separate function, which is also exported from the ChildForm.jsx. Having done that, you can probably guess what I'm going to do in the Parent.jsx module! Let's take a look:
import reactUpdate from 'react-addons-update';
import ChildForm from "./ChildForm.jsx";
import {getDefaultProps as getChildFormDefaultProps} from "./ChildForm.jsx";
class Parent extends React.Component {
constructor(props) {
super(props);
var formDefaultProps = getChildFormDefaultProps();
this.state = {
formData: formDefaultProps
};
this.handleFormFieldChange.bind(this);
}
handleFormFieldChange(e) {
var newState = reactUpdate(this.state, {
formData: {values: {formFieldValues: {[e.currentTarget.name]: {$set: e.currentTarget.value}}}}
});
this.setState(newState);
}
render() {
return (
<div>
<ChildForm
formData={this.state.formData}
handleFieldChange={this.props.handleFormFieldChange} /}
</div>
);
}
}
I import the getDefaultProps function from the ChildForm.jsx module and then use that to set the default state for ChildForm at the Parent.jsx level. That state is then passed down to ChildForm as props.
Although this works, I can't help feeling that it's rather clunky. Although I'm defining the defaultProps at the ChildForm.jsx level, where they should be, they're never actually used as defaultProps at that level! Rather, they're passed up the Parent, which uses them to set state, which in turn is passed down to ChildForm as real props.
Still, this is preferable to having to define a default state for the ChildForm component all over again in the Parent component. So it will do for now, unless any of you kind people can suggest something cleaner!

Resources