What is the proper way to handle React state and props - reactjs

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;

Related

Updating parent component without a call back function in react js

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
})
}

React: Passing child state to parent state

I am working since more than a year with React and i have read Thinking in react, Lifting state up, and State and lifecycle.
I have learned that React's concept with data flow is is One-way data flow.
Citates from these pages:
React’s one-way data flow (also called one-way binding) keeps everything modular and fast.
Remember: React is all about one-way data flow down the component hierarchy. It may not be immediately clear which component should own what state. This is often the most challenging part for newcomers to understand, so follow these steps to figure it out:...
If you imagine a component tree as a waterfall of props, each component’s state is like an additional water source that joins it at an arbitrary point but also flows down.
As i understand this, following example is not allowed because i am passing child state data to the parent. But i see some developers working like that:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { fromParent: null };
}
addSomething(stateValueFromChild) {
this.setState({fromParent: stateValueFromChild});
}
render() {
return <Child
addSomething={(stateValueFromChild) => this.addSomething(stateValueFromChild)}>
// ...
</Child>;
}
}
class Child extends React.Component {
constructor(props) {
super(props);
this.state = { fromChild: 'foo' };
}
render() {
return <Form onSubmit={() => this.props.addSomething(this.state.fromChild)}>
// ...
</Form>;
}
}
My questions now are:
Is this really not allowed?
Why should this not be modular and fast?
Is this really braking the one-way-dataflow, becoming a two way dataflow?
What other problems could happen with this way?
When i would lift the state up, how would you solve following case; 50 concrete parents that uses that child component, should every parent have a same initialized sub-state for the same child that they are using?
Is this really not allowed?
Why should this not be modular and fast?
Excellent questions. This is allowed. It's just a bit tricky to make it work right because you've got state synchronization here. In the modern frontend world, the state synchronization is believed to be a very challenging task.
The problem will appear when you'll need to sync the state in two directions. For instance, if this child form is used to edit some element of the list, and you're changing the current element of the list. You'll need the child component to detect that situation and sync its local state with the new element from props during the particular UI update. As long as you don't have that, you're fine.
Is this really braking the one-way-dataflow, becoming a two way dataflow?
Nah, it's not. It's still unidirectional data flow because React can't work in any other way by design; UI updates always coming from top to bottom. In your example, your child triggers an event which causes the parent to update its state (it's totally fine), which will cause the UI update of the parent and the child. If you really violate "unidirectional data flow", you'll feel it. You will get an infinite loop or something similar.
When i would lift the state up, how would you solve following case; 50 concrete parents that uses that child component, should every parent have a same initialized sub-state for the same child that they are using?
Yep, that's what they mean by "lifting the state". You organize your root state as a tree reflecting the state of the children, then pass down elements of the state to children along with callbacks to modify the root state.
It's allowed and there is nothing wrong with your code, but I would not call it passing state from child to parent. All you do is invoking method passed in props and triggered by event with some argument, which in your example is child's state value, but it could be any other variable. Parent component knows nothing about nature of this argument, it just receives the value and able to do anything with it, for example change it's own state to another. If Child's state will change, Parent is not going to receive this update without onSubmit event fired again. But children always receive updates from the parent and automatically get rerendered, when props get changed. And of course some of the props could be states of some parents. Here is the major difference in behavior.
There is a good article explaining this in details: Props down, Events Up
Your question is absolutely correct, many times developer (including myself) struggled for passing child's components state or props to parent component.
I always do logic for getting next state or next props in child component and pass next state or next props to parent component by using handler functions of parent component.
import React, { Component } from "react";
import { render } from "react-dom";
class Parent extends Component {
constructor(props) {
super(props);
this.handleSomething = this.handleSomething.bind(this); // binding method
this.state = {
fromParent: "foo"
};
}
handleSomething(value) {
this.setState(prevState => {
return {
fromParent: value
};
});
}
render() {
return (
<div>
<h1>State: {this.state.fromParent}</h1>
<Child handleSomething={this.handleSomething} />
</div>
);
}
}
class Child extends Component {
constructor(props) {
super(props);
this.state = {
fromChild: "bar"
};
}
render() {
return (
<div>
<button
onClick={e => {
const { fromChild } = this.state;
// do whatever as per your logic for get value from child pass to handleSomething function
// you can also do same for handling forms
this.props.handleSomething(fromChild);
}}
>
Click Me
</button>
</div>
);
}
}
render(<Parent />, document.getElementById("app"));

child component update parent component

I just wonder if it is good that the child component updates the parent component.
in the source code, like following
class Parent extends React.Component{
state = {
name : ''
}
changeState = ((state) => {
this.setState(state)
})
submit = (() => {
// send state to api..
})
render(){
return(
<div>
<Child changeState={this.changeState} {...this.state}/>
<button onClick={this.submit} />
</div>
)
}
}
class Child extends React.Component{
change = ((e) => {
this.props.changeState({
name : e.target.value
})
})
render(){
return(
<input onChange={this.change} value={this.props.name} />
)
}
}
the reason I use this way is submitting method.
There are many input tags, and I want to bind them all together.
but I'm not sure this way is good or not.
because when I type something, parent component always will rerender.
I think it is not good.(actually it just my thinking...)
is it right?
I have used this way to update state of a parent from a child. It does work properly. But it makes the components little complex.
In your case (assuming you do this for text input elements) I don't think this will be a good practice if you are doing it for tiny input components. Because every time you hit a key on a keyboard the parent component will try to update.
But if you are wrapping a set of input elements and pass a larger object to a parent component I think that will be fine.
You could use react life cycle method shouldComponentUpdate() method to control the rendering of the parent component
shouldComponentUpdate
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
shouldComponentUpdate(nextProps, nextState) {
if (this.props.name != nextProps.name) {
return true;
} else {
return false;
}
}
Here nextProps refers to the props you receive(updates) and you can refer to current prop values by "this.props"
And return true to render and false to skip the rendering.
If you have perform validations when the user inputs, then its ok.
Otherwise change 'onChange' event to 'onBlur'
Its a good idea to lift the state up and update it in the parent if multiple other siblings want to refer to the same values. You can optimise on this my making your Parent and Child Components pure as long as they don't have complex and deeply nested props and states.
According to the React docs:
React.PureComponent is exactly like React.Component, but
implements shouldComponentUpdate() with a shallow prop and state
comparison. If your React component’s render() function renders the
same result given the same props and state, you can use
React.PureComponent for a performance boost in some cases.
Re-rendering of parent is not a problem as long as it is not wasted. And Unless you are using Redux, I think this is a proper way to manage the state, i.e., inside the parent component and updating it using the child. In this way, you have made your form into a controlled component.
I think the following page will be useful to you: https://scotch.io/courses/getting-started-with-react/parent-child-component-communication

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!

Updating state in more than one component at a time

I have a listview component which consists of a number of child listitem components.
Each child listitem have a showSubMenu boolean state, which display a few extra buttons next to the list item.
This state should update in response to a user event, say, a click on the component DOM node.
childcomponent:
_handleClick() {
... mutate state
this.props.onClick() // call the onClick handler provided by the parent to update the state in parent
}
However, it feels somewhat wrong to update state like, as it mutates state in different places.
The other way i figured i could accomplish it was to call the this.props.onClick directly, and move the child state into the parent as a prop instead, and then do change the state there, and trickle it down as props.
Which, if any, of these approaches is idiomatic or preferable?
First of all, I think that the question's title doesn't describe very well what's your doubt. Is more an issue about where the state should go.
The theory of React says that you should put your state in the higher component that you can find for being the single source of truth for a set of components.
For each piece of state in your application:
Identify every component that renders something based on that state.
Find a common owner component (a single component above all the
components that need the state in the hierarchy).
Either the common
owner or another component higher up in the hierarchy should own the
state.
If you can't find a component where it makes sense to own the
state, create a new component simply for holding the state and add it
somewhere in the hierarchy above the common owner component.
However, a Software Engineer at Facebook said:
We started with large top level components which pull all the data
needed for their children, and pass it down through props. This leads
to a lot of cruft and irrelevant code in the intermediate components.
What we settled on, for the most part, is components declaring and
fetching the data they need themselves...
Sure, is talking about data fetched from stores but what im traying to say is that in some cases the theory is not the best option.
In this case i would say that the showSubMenu state only have sense for the list item to show a couple of buttons so its a good option put that state in the child component. I say is a good option because is a simple solution for a simple problem, the other option that you propose means having something like this:
var GroceryList = React.createClass({
handleClick: function(i) {
console.log('You clicked: ' + this.props.items[i]);
},
render: function() {
return (
<div>
{this.props.items.map(function(item, i) {
return (
<div onClick={this.handleClick.bind(this, i)} key={i}>{item} </div>
);
}, this)}
</div>
);
}
});
If, in a future, the list view has to get acknowledge of that state to show something for example, the state should be in the parent component.
However, i think it's a thin line and you can do wathever makes sense in your specific case, I have a very similar case in my app and it's a simple case so i put the state in the child. Tomorrow maybe i must change it and put the state in his parent.
With many components depending on same state and its mutation you will encounter two issues.
They are placed in component tree so far away that your state will have to be stored in a parent component very high up in the render tree.
Placing the state very high far away from children components you will have to pass them down through many components that should not be aware of this state.
THERE ARE TWO SOLUTIONS FOR THIS ISSUE!
Use React.createContext and user context provider to pass the data to child elements.
Use redux, and react-redux libraries to save your state in store and connect it to different components in your app. For your information react-redux library uses React.createContext methods under the hood.
EXAMPLES:
Create Context
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
// Use a Provider to pass the current theme to the tree below.
// Any component can read it, no matter how deep it is.
// In this example, we're passing "dark" as the current value.
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
}
// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// Assign a contextType to read the current theme context.
// React will find the closest theme Provider above and use its value.
// In this example, the current theme is "dark".
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
REDUX AND REACT-REDUX
import { connect } from 'react-redux'
const App = props => {
return <div>{props.user}</div>
}
const mapStateToProps = state => {
return state
}
export default connect(mapStateToProps)(App)
For more information about redux and react-redux check out this link:
https://redux.js.org/recipes/writing-tests#connected-components

Resources