I'm lifting state up from child to parent and trying to render select elements with data from HTTP request. The select tag values within the Inv
child component will show previously selected values, but I'm getting this error:
Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
It looks like the error is coming from the Inv
child component that is being passed props with this.state.identInvsData
. That is the only time I get the error. The child components in the else statements that don't get the identInvsData
don't get that error message. The parent component does not re-render, or "mount" the children.
Any ideas as to what I'm doing wrong?
Edit: The child components are populating the data from HTTP endpoint, but onChange it doesn't change the values in
setState
, only when I select the buttonAdd Inv
. It adds another child but also allows the previous children to change.
Identity Parent Component
class Identity extends React.Component {
state = {
invIds: [],
inTypes: [],
invSeqIds: [],
numChildren: 0,
addInvBtnPressed: false
};
handleAddInv = () => {
this.setState({
numChildren: this.state.numChildren + 1,
addInvBtnPressed: true
});
};
onChangeInv = (e, index, sId) => {
const invIdsArry = this.state.invIds;
const invSeqIdsArry = this.state.invSeqIds;
const newId = [
...invIdsArry.slice(0, index),
(invIdsArry[index] = e.target.value),
...invIdsArry.slice(index + 1)
];
if (sId) {
const newSeqId = [
...invSeqIdsArry.slice(0, index),
(invSeqIdsArry[index] = sId),
...invSeqIdsArry.slice(index + 1)
];
this.setState({ invIds: newId, invSeqIds: newSeqId });
} else {
this.setState({ invIds: newId });
}
};
onChangeType = (e, index) => {
const invTypesArry = this.state.invTypes;
const newTypes = [
...invTypesArry.slice(0, index),
(invTypesArry[index] = e.target.value),
...invTypesArry.slice(index + 1)
];
this.setState({ invTypes: newTypes });
};
render() {
const children = [];
var i;
if (this.state.identInvsData && !this.state.addInvBtnPressed) {
for (i = 0; i < this.state.numChildren; i += 1) {
children.push(
<Inv
key={i}
invKey={i}
onChangeInv={this.onChangeInv.bind(this)}
onChangeType={this.onChangeType.bind(this)}
invId={this.state.identInvsData[i].invId}
invType={this.state.identInvsData[i].invTypeCd}
seqId={this.state.identInvsData[i].seqId}
invData={this.state.identInvsData[i]}
/>
);
}
} else if (this.state.identInvsData && this.state.addInvBtnPressed) {
for (i = 0; i < this.state.numChildren; i += 1) {
children.push(
<Inv
key={i}
invKey={i}
onChangeInv={this.onChangeInv.bind(this)}
onChangeType={this.onChangeType.bind(this)}
/>
);
}
} else {
for (i = 0; i < this.state.numChildren; i += 1) {
children.push(
<Inv
key={i}
invKey={i}
onChangeInv={this.onChangeInv.bind(this)}
onChangeType={this.onChangeType.bind(this)}
/>
);
}
}
return (
<div>
<button
type="button"
className="btn btn-info"
onClick={this.handleAddInv}
>
Add Inv
</button>
<div>{children}</div>
</div>
)
}
}
export default Identity;
Inv Child Component
class Inv extends React.Component {
state = {
kddLookupData: "",
invData: ""
};
componentDidMount = () => {
kddlookups_getAll().then(resp => {
this.setState({
kddLookupData: resp.data.item
});
});
invs_getAll().then(resp => {
this.setState({
invData: resp.data.items
});
});
};
handleInvestigatorChange = e => {
this.props.onChangeInv(e, this.props.invKey, this.props.seqId);
};
handleInvestigatorTypeChange = e => {
this.props.onChangeType(e, this.props.invKey);
};
render() {
return (
<div>
<select
value={this.props.invId}
name={this.props.invKey}
onChange={this.handleInvChange.bind(this)}
>
<option className="blank">Select inv name:</option>
{this.state.invData &&
this.state.invData.map(inv => {
return (
<option key={inv.userId} value={inv.userId}>
{inv.invName}
</option>
);
})}
</select>
<select
value={this.props.invType}
name={this.props.invKey}
onChange={this.handleInvTypeChange.bind(this)}
>
<option className="blank">Select inv type:</option>
{this.state.kddData &&
this.state.kddData.kdd_inv_type.map(inv => {
return (
<option key={inv.inv_type_cd} value={inv.inv_type_cd}>
{inv.inv_type_name}
</option>
);
})}
</select>
</div>
)
}
}
export default Inv;
It doesn't look like you are returning anything in your render function in the child component. Try:
render() {
return (
<div>
<select
value={this.props.invId}
name={this.props.invKey}
onChange={this.handleInvChange.bind(this)}
>
<option className="blank">Select inv name:</option>
{this.state.invData &&
this.state.invData.map(inv => {
return (
<option key={inv.userId} value={inv.userId}>
{inv.invName}
</option>
);
})}
</select>
<select
value={this.props.invType}
name={this.props.invKey}
onChange={this.handleInvTypeChange.bind(this)}
>
<option className="blank">Select inv type:</option>
{this.state.kddData &&
this.state.kddData.kdd_inv_type.map(inv => {
return (
<option key={inv.inv_type_cd} value={inv.inv_type_cd}>
{inv.inv_type_name}
</option>
);
})}
</select>
</div>
);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.