When I'm sending state of the child component to its parent component, React is sending old state to the parent component.
I want to send the updated state on every click on ListItem which is properly working and calling the function handleItemClick.
But when I'm calling sendStateToParent
. It is passing old state of it. Suppose I have clicked on ITEM1
, it is sending empty array[]
. Next I have clicked on ITEM2
, it is sending array [ITEM1]
.
Here I'm actually creating a multiselect dropdown. which also can act as single select based on props it is getting.
import React from 'react';
import ListItemComponent from './ListItem.jsx';
import DropDownButtonComponent from './DropDownButton.jsx';
import DropDownStyle from '../../../../css/sass/drop-down.scss';
module.exports = React.createClass({
handleClick: function () {
this.setState({open: !this.state.open});
},
getInitialState: function () {
return {
open: false,
//listItems: this.props.listItems,
selectedItems:[],
title: this.props.dropdownTitle
}
},
handleItemClick: function (item) {
var selectedItems = [];
if(this.props.multiple == true){
selectedItems = this.state.selectedItems;
if(selectedItems.indexOf(item)==-1){
selectedItems.push(item);
}else{
selectedItems.splice(selectedItems.indexOf(item),1)
}
this.setState({
title: this.state.selectedItems.length+" selected",
selectedItems: selectedItems
});
} else{
selectedItems = [];
selectedItems.push(item);
this.setState({
title: item,
selectedItems: selectedItems,
open: false
});
}
this.sendStateToParent();
},
sendStateToParent: function(){
this.props.ifListChanged(this);
},
handleTextChange: function (event) {
var filteredItems = [];
this.props.listItems.map(function(item){
if(item.toLowerCase().search(event.target.value.toLowerCase()) != -1){
filteredItems.push(item);
}
},this);
this.setState({
listItems: filteredItems
});
},
clearSelected: function(){
this.setState({
title: this.props.dropdownTitle,
selectedItems: [],
});
},
render: function () {
var index = 0;
var list=[];
if (this.state.listItems != undefined) {
list = this.state.listItems.map(function (item) {
return (
<ListItemComponent
key={index++}
item={item}
whenItemClicked={this.handleItemClick}
className={this.state.selectedItems.indexOf(item) != -1 ? "active" : ""}
/>);
}.bind(this));
} else {
list = this.props.listItems.map(function (item) {
return (
<ListItemComponent
key={index++}
item={item}
whenItemClicked={this.handleItemClick}
className={this.state.selectedItems.indexOf(item) != -1 ? "active" : ""}
/>);
}.bind(this));
}
return <div className="btn-group bootstrap-select form-control">
<DropDownButtonComponent
whenClicked={this.handleClick}
title={this.state.title}
/>
<ul className={"dropdown-menu inner dropdown-menu " + (this.state.open ? "show" : "") }>
{this.props.search? <li><input type="text" style={{margin:"auto", maxWidth:"96%"}} onChange={this.handleTextChange} placeholder="Search"/></li> :""}
<li className="disabled"><a>Select from below list {this.props.multiple ? <i title="clear all" style={{fontSize:"15px"}} onClick={this.clearSelected} className="text-danger fa fa-ban pull-right"></i>: ""}</a></li>
{list}
</ul>
</div>
}
});
Thanks in advance
So in your code, you send a request to update state, and before the new state is processed, you call the method in the parent, to inform parent about state, which still has the old items. Fix 1:send current state to parent. To get the item to send the current state, you could use the callback that setState()provides. Explained also in react pages:
— React Context provides a way to pass data through the component tree without having to pass props down manually at every level ☘️ In any application, data is essential. We all know this, in React, state and props are two very important properties and are commonly used, easily explained: they are all used to save the state of the data.
You pass the callback method to the child when it's created. class Parent extends React.Component { myCallback = (dataFromChild) => { //use dataFromChild }, render() { return ( <div> <ComponentA callbackFromParent={this.myCallback}/> </div> ); } }
Step 1: Create a React application using the following command: Step 2: After creating your project folder, i.e., folder name, move to it using the following command: Project Structure: It will look like the following. Step 3: Now create Parent and Children components in the src folder with the following code.
The reason parent gets the old value of selecteditems, is because setState()
is an asynchronous operation. See explanation here:
setState()
does not immediately mutatethis.state
but creates a pending state transition. Accessingthis.state
after calling this method can potentially return the existing value.
So in your code, you send a request to update state, and before the new state is processed, you call the method in the parent, to inform parent about state, which still has the old items.
Fix 1: send current state to parent.
To get the item to send the current state, you could use the callback that setState()
provides. Explained also in react pages:
The second (optional) parameter is a callback function that will be executed once
setState
is completed and the component is re-rendered.
This ensures that the call to parent is made only after setState()
is finished. Something like this:
this.setState(
{
title: item,
selectedItems: selectedItems,
open: false
},
this.sendStateToParent
);
Fix 2(optional but recommended): move selecteditems state to parent.
If your parent needs to know about selecteditems, I would advise not to put these in state of the list. The only thing your component does with the selecteditems is to send them to the parent, every time an item is clicked.
Instead, it is better to:
handleItemClick
logic to the parentIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With