Can't use checkbox correctly to update state - reactjs

I am using a checkbox that should update a todo item's completed status via the component's state. When I click the todo box it doesn't change state, but if I click it two times, it does update the state. Since I have to click it two times, that means when the box is checked this.state.done === false and when it is uncheck this.state.done === true. I don't know why it doesn't flip the state on the first click. The checkbox is controlled by handleDoneChange(). Could someone tell me why the checkbox doesn't change the state on the first click?
class ShowTodo extends Component {
static contextTypes = {
router: PropTypes.object
};
constructor(props) {
super(props);
this.state = {
descriptionChanged: false,
newDescription: '',
newTitle: '',
done: false
};
this.handleDescriptionChange = this.handleDescriptionChange.bind(this);
this.handleDeleteClick = this.handleDeleteClick.bind(this);
this.changeButtons = this.changeButtons.bind(this);
this.handleSaveClick = this.handleSaveClick.bind(this);
this.handleUndoClick = this.handleUndoClick.bind(this);
this.handleTitleChange = this.handleTitleChange.bind(this);
this.handleDoneChange = this.handleDoneChange.bind(this);
}
componentWillMount() {
this.props.fetchTodo(this.props.params.id).then(() => {
this.setState({
newDescription: this.props.todo.description,
newTitle: this.props.todo.title,
done: this.props.todo.completed
});
console.log("This is the todo's starting completed status: ", this.state.done);
});
}
render() {
const { todo } = this.props;
if (!todo) {
return (
<h3>Loading...</h3>
);
}
return (
<div className="input-group">
<Link to="/todos_index">Back</Link>
<h3>Title</h3>
<input
type="text"
className="form-control"
value={this.state.newTitle}
onChange={this.handleTitleChange} />
<textarea
className="form-control"
value={this.state.newDescription}
onChange={this.handleDescriptionChange}>
</textarea>
<span className="input-group-addon">
<input type="checkbox"
onClick={this.handleDoneChange} />
</span>
<span className="input-group-btn">
{this.changeButtons()}
<button onClick={this.handleDeleteClick} className="btn btn-danger pull-xs-right">Delete Post</button>
</span>
</div>
);
}
changeButtons() {
if (!this.state.descriptionChanged) {
return null;
} else {
return [
<button
className="btn btn-default"
onClick={this.handleSaveClick}
>Save</button>,
<button
className="btn btn-default"
onClick={this.handleUndoClick}
>Undo</button>
];
}
}
handleDescriptionChange(event) {
this.setState({
descriptionChanged: true,
newDescription: event.target.value
});
console.log('New description in state: ', this.state.newDescription);
}
handleTitleChange(event) {
this.setState({
descriptionChanged: true,
newTitle: event.target.value
});
}
handleDoneChange(event) { //This isn't updating the done status
this.setState({
done: !this.state.done
});
var id = this.props.params.id;
var props = {
completed: this.state.done
};
console.log(props);
this.props.updateTodo(id, JSON.stringify(props));
}
handleDeleteClick(event) {
this.props.deleteTodo(this.props.params.id).then(() => {
this.context.router.push('/todos_index');
});
}
handleSaveClick(event) {
var id = this.props.params.id;
var props = {
title: this.state.newTitle,
description: this.state.newDescription
};
this.props.updateTodo(id, JSON.stringify(props)).then(() => {
this.context.router.push('/todos_index');
});
}
handleUndoClick() {
this.setState({
descriptionChanged: false,
newTitle: this.props.todo.title,
newDescription: this.props.todo.description
});
}
}
function mapStateToProps(state) {
return { todo: state.todos.todo };
}
export default connect(mapStateToProps, { fetchTodo, updateTodo, deleteTodo })(ShowTodo);

Checkboxes should use onChange rather than onClick.
EDIT: There's another issue.
Your component is working correctly. Your debug console.log is not.
this.setState is asynchronous, so you won't see the changes in the following lines of code. If you want to do something after the state has finished changing, you should pass it as a callback to the setState function:
this.setState({
descriptionChanged: true,
newDescription: event.target.value
}, function(){
console.log('New description in state: ', this.state.newDescription);
}
});

Related

Unable to change the value in the object

My objective is to change the value of the object to true or false while onchanging the checkbox.
Object contains:
{
id: '12497wewrf5144',
name: 'ABC',
isVisible: 'false'
}
Here is the code:
import React, { Component } from 'react'
class Demo extends Component {
constructor(props) {
super(props)
this.state = {
demo: {}
}
}
componentDidMount() {
axios
.get('/api/random')
.then(res => {
this.setState({ demo: res.data?.[0] })
})
.catch(error => {
console.log(error)
})
}
render() {
return (
<div>
<h1>{this.state.demo.name}</h1>
<input type="checkbox" value={this.state.demo.value} />
</div>
)
}
}
export default Demo
I don't know what to write in onchange method for checkbox to only change the value within the object.
Can anyone help me in this query?
<input
type="checkbox"
value={this.state.demo.value}
onChange={(event) => {
this.setState((prevState) => ({
...prevState,
demo: { ...prevState.demo, isVisible: event.target.checked }
}));
}}
/>
Given your state ends up looking like
this.state = {
demo: {
id: "12497wewrf5144",
name: "ABC",
isVisible: "false",
value: false
}
};
You can create a change handler as such
changeHandler = e => {
e.preventDefault();
const { checked } = e.target;
this.setState(prevState => ({
...prevState, // <-- spread existing state
demo: {
...prevState.demo, // <-- spread existing demo
value: checked, // <-- save the input's checked value
}
}))
}
Attach the changeHandler to the onChange event callback
<input
type="checkbox"
onChange={this.changeHandler}
value={this.state.demo.value}
/>
Ciao, you could use onClick event like this:
...
handleClick = (e, data) => {
const demo = { ...this.state.demo };
demo.isVisible = !demo.isVisible;
this.setState({ demo });
}
...
<input type="checkbox" value={this.state.demo.value} onClick={((e) => this.handleClick(e, data))}/>
...

All the toasters close when clicked on the close button in react

I have made a toaster component of my own which on multiple clicks render multiple toasters. The problem I am facing is that all the toasters are terminated when the handle close component is clicked or when the settimeout function is called. I am passing messages through another component as props.
This is my toaster component
export default class MyToaster extends React.Component {
constructor(props) {
super(props);
this.state = {
message: props.message,
show: false,
no: 0
};
}
handleclose = () => {
this.setState({
show: false,
no: this.state.no - 1
})
}
handleOpen = () => {
console.log('HANDLE OPEN')
this.setState({
show: true,
no: this.state.no + 1
}, () => {
setTimeout(() => {
this.setState({
show: false,
no: this.state.no - 1
})
}, 3000)
})
}
createtoaster = () => {
if (this.state.show) {
let toastmessage = [];
for (let i = 0; i < this.state.no; i++) {
let tmessage = <div className="snackbar">
<div className="card-header">
<h3 className="card-title">Toast</h3>
</div>
<div className="card-body">
{this.state.message}
</div>
<div className="card-footer"></div>
<button className="btn" onClick={this.handleclose}>x</button>
</div>
toastmessage.push(tmessage);
}
return toastmessage;
} else {
return null;
}
};
render() {
return (
<div className="col-md-2 offset-md-9">
<button className="btn btn-primary" onClick={this.handleOpen}></button>
{this.createtoaster()}
</div>
)
}
}
I have tried managing the state in the parent component but it doesnt seem to work. I do know that the problem is in managing state of my toaster component but dont know the exact problem and the solution.
Any solutions for this also feel free to point out any of my mistakes.
TIA
Handle close is run on the click of any button rather on the instance of one of them by the looks of it.
if (this.state.show) { // this determines whether to render you toasts...
// and close turns all of them off.
You need to change each toast to have it's own show property and for close to toggle that one and remove it from the array of toasts to generate.
Note:
Your props and state should be separate, don't copy props into state as this will introduce bugs and changes will not be reflected.
constructor(props) {
super(props);
// avoid copying props into state
// https://reactjs.org/docs/react-component.html#constructor
this.state = {
message: props.message,
show: false,
no: 0
};
}
There is a different way to this approach.
export default class MyToaster extends React.Component {
constructor(props) {
super(props);
this.state = {
message: props.message,
show: true,
no: 0
};
}
componentDidMount() {
setTimeout(() => {
this.setState({show: false})
}, 4000)
}
handleclose = () => {
this.setState({
show: false,
no: this.state.no - 1
})
}
handleOpen = () => {
this.setState({
no: this.state.no + 1
}, () => {
setTimeout(() => {
this.setState({
show: false,
no: this.state.no - 1
})
}, 3000)
})
}
render() {
return (
<div className="col-md-2 offset-md-9">
{this.state.show
? (
<div className="container snackbar" style={this.props.style}>
<div className="card-header">
<h3 className="card-title">Toast</h3>
</div>
<div className="card-body">
{this.props.message}
</div>
<div className="card-footer"></div>
</div>
)
: null
}
</div>
)
}
}
And from your parent component you can include
this.state = {
toasterCollection: []
}
//make a function
handleToasterClick = () => {
const toaster = <Toaster message={this.message} style={this.style}/>
this.setState({
// toasterCollection: [...this.state.toasterCollection, toaster]
toasterCollection: [...this.state.toasterCollection, toaster]
});
}
//In your Render give a button
<button className="btn btn-primary" onClick={this.handleToasterClick}>
Toast
</button>
//Also render this
{this.state.toasterCollection}
This should get your code to work.

Update Apollo store after filtered query

I have a list of items which can be filtered out using certain criteria. Whenever i perform a search, i want to grab a filtered item and update its content which seems to update the apollo store correctly, but for some reason changes are not being shown. Perhaps the componentWillReceiveProps lifecycle method is not being fired and i need to implement it by myself?
I tried updating the store manually using "update" after the mutation but it wont work also.
This is my code so far:
ClientList.js
class ClientList extends Component {
constructor(props) {
super(props);
this.state = {
hasMoreItems: true,
loading: false,
clients: [],
searchText: ''
}
}
_executeSearch = async () => {
const { searchText } = this.state;
this.setState({ loading: true });
const result = await this.props.client.query({
query: ALL_CLIENTS_QUERY,
variables: { searchText },
fetchPolicy: 'network-only'
})
this.setState({
clients: result.data.allClients,
loading: false
});
}
render() {
let { allClients, loading, fetchMore } = this.props.data;
const { hasMoreItems, clients, searchText } = this.state;
if (clients.length > 0) {
allClients = clients;
loading = this.state.loading;
}
return (
<section>
<h1 className="text-center">Clients</h1>
<InputGroup>
<InputGroupButton>
<Button onClick={() => this._executeSearch()}>I'm a button</Button>
</InputGroupButton>
<Input
onChange={(e) => this.setState({ searchText: e.target.value })}
placeholder="Search by social or comercial name"
/>
</InputGroup>
{loading ?
<div className="text-center mt-4">
<i className="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>
</div>
: <div className="mt-3">
{allClients.map(client =>
<div key={`client-${client.id}`} className="client-content">
<Link to={`/clients/${client.id}`}>
<h1 className="mb-1">
{client.socialName}
<small className="text-muted ml-3">{client.comercialName}</small>
</h1>
</Link>
</div>
})
</div>
</section>
);
};
}
export default withApollo(graphql(ALL_CLIENTS_QUERY)(ClientList));
ClientEdit.js
class ClientEdit extends Component {
onSubmit = async (e) => {
e.preventDefault();
this.setState({ loading: true });
const payload = {
id: this.props.match.params.id,
rfc: this.state.rfc,
socialName: this.state.socialName,
legalRepresentative: this.state.legalRepresentative,
comercialName: this.state.comercialName
}
// Mutation updates the store but doesnt show results
const resp = await this.props.mutate({
variables: payload,
update: (store, { data: { updateClient } }) => {
// Tried updating but it doesnt show changes also;
}
});
}
}
export default compose(
graphql(GET_CLIENT_QUERY, {
options: props => ({
variables: {
id: props.match.params.id
}
})
}),
graphql(UPDATE_CLIENT_MUTATION)
)(ClientEdit);
better if we check that the data is ready and we can render it out , and when data still fetching so no render associated with that apollo data object should be done:
render(){
const {loading} = this.props.data;
if(loading) {return <div>Loading...</div>}
return (
...
)
I manage to fix this using the componentWillReceiveProps lifecycle method. I dont know if this is a bug or maybe there is another solution;
componentWillReceiveProps(newProps) {
const { allClients, loading } = newProps.data;
if (!loading) {
const clients = _.intersectionBy(allClients, this.state.clients, 'id');
this.setState({ clients });
}
}

React - conditional render fails trying to display component for the second time

I am creating a React Component to manage the user Input.
This Component, UserInput.js, has the following methods,
renderOrigin - displays a Form component,
renderCities - displays the same form component with diferent props,
renderAddCitiesQuestion - renders two buttons (yes or no) which are handled by,
handleContinue - sets state with the answer to 'continue' question
getChildSate - sets the state received by the child components (like the form)
render - Conditional rendering based on the state. State has the boolean properties, 'start' (for the first render), 'rendercities' and 'renderQuestion'.
The flow of the conditional is as follows.
First, state.start is true and we call renderOrigin;
than, state.start becomes false, state.renderCities becomes true, and we call renderCities(); than, state.rendercities becomes false and state.renderQuestion becomes true, which makes us call renderAddCityQuestion(); now there are two possibilites, either the user clicks the No button, and we should render nothing, or he clicks Yes and state.renderCities becomes true ( and state.renderQuestion becomes false) which calls renderCities() (and it is called, i see it via console.log) but that component is NOT rendered, while the question component remains visible.
I can not see to find the mistake.
Here is the entirety of the code.
import React from 'react';
import Form_city from './Form_city';
class UserInput extends React.Component {
constructor(props) {
super(props);
this.getChildState = this.getChildState.bind(this);
this.handleContinue = this.handleContinue.bind(this);
this.renderOrigin = this.renderOrigin.bind(this);
this.renderCities = this.renderCities.bind(this);
this.renderAddCitiesQuestion = this.renderAddCitiesQuestion.bind(this);
this.state = {
origin: null,
cities: [],
renderCities: false,
renderQuestion: false,
start: true
}
}
getChildState(stateName, stateVal) {
console.log('setting state. received stateName, stateVal', stateName, stateVal);
this.setState({
[stateName] : stateVal
});
console.log('set state done: ', this.state);
}
handleContinue(answer) {
this.state.renderQuestion = false;
answer === 'yes' ? this.state.renderCities = true : this.state.renderCities = false;
console.log('state after clicking answer: ', this.state);
this.render();
}
renderOrigin() {
return(
<div>
<Form_city
divName="originForm"
text="Please select an Origin:"
type="origin"
placeHolder="Origin"
getChildState={this.getChildState}
/>
</div>
);
}
renderCities() {
console.log('rendering city form');
return(
<div>
<Form_city
divName="citiesForm"
text="Which city do you want to visit?"
type="cities"
placeholder="Destination"
getChildState={this.getChildState}
/>
</div>
);
}
renderAddCitiesQuestion() {
console.log('rendering question');
return(
<div>
<p>Do you want to visit any other city?</p> <br />
<button type="button" onClick={this.handleContinue.bind(this, 'yes')}>Yes</button>
<button type="button" onClick={this.handleContinue.bind(this, 'no')}>No</button>
</div>
);
}
render() {
console.log('inside render\n, state: ', this.state);
let content = null;
if (this.state.start === true) {
console.log('inside render origin conditional');
content = this.renderOrigin();
} else if (this.state.renderCities === true) {
console.log('inside render cities conditional');
content = this.renderCities();
} else if (this.state.renderQuestion === true) {
console.log('inside render question conditional');
content = this.renderAddCitiesQuestion();
} else {
content = <p>Weird stuff?</p>
}
return(
<div> {content} </div>
);
}
}
export default UserInput;
here is also the Form component for completeness sake.
import React from 'react';
class Form_city extends React.Component {
constructor(props) {
super(props);
this.state = {data: ''};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState( {data: event.target.value} );
}
handleSubmit(event) {
console.log('clicked submit button');
event.preventDefault();
if (this.props.type === 'origin') {
console.log('inside handle submit Origin, passing: ', this.state.data);
this.props.getChildState('start', false);
this.props.getChildState('origin', this.state.data);
this.props.getChildState('renderCities', true);
} else if (this.props.type === 'cities') {
console.log('inside handle submit Cities');
this.props.getChildState('cities', this.state.data);
this.props.getChildState('renderCities', false);
this.props.getChildState('renderQuestion', true);
}
}
render() {
return(
<div className = {this.props.divName}>
<form onSubmit = {this.handleSubmit}>
<label>
{this.props.text} <br />
<input
type="text"
placeholder={this.props.placeholder}
value={this.state.data}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}
export default Form_city;
Your way to update a state is incorrect, you need to use setState if you want to re-render component with a new state:
handleContinue(answer) {
if (answer === 'yes'){
this.setState({
renderQuestion: false,
renderCities: true,
renderCities: false
})
}
}
Pretty good explanation why: https://stackoverflow.com/a/40309023/7132340
And docs.

React force componentDidMount

I have the following:
import React from 'react';
import axios from 'axios';
class FirstName extends React.Component {
constructor(props) {
super(props);
this.state = {
submitted: false
};
}
getName () {
var name = this.refs.firstName.value;
this.setState(function() {
this.props.action(name);
});
}
handleSubmit (e) {
e.preventDefault();
this.setState({ submitted: true }, function() {
this.props.actionID(2);
this.props.activeNav('color');
});
}
render () {
return (
<div>
<h2>tell us your first name</h2>
<form>
<input
type="text"
ref="firstName"
onChange={this.getName.bind(this)}
/>
<div className="buttons-wrapper">
<button href="#">back</button>
<button onClick={this.handleSubmit.bind(this)}>continue</button>
</div>
</form>
</div>
);
}
};
class PickColor extends React.Component {
backToPrevious (e) {
e.preventDefault();
this.props.actionID(1);
this.props.activeNav('name');
}
goToNext (e) {
e.preventDefault();
this.props.actionID(3);
this.props.activeNav('design');
this.props.displayIconsHolder(true);
}
getColorValue(event) {
this.props.color(event.target.getAttribute("data-color"));
}
render () {
var colors = ['red', 'purple', 'yellow', 'green', 'blue'],
colorsLink = [];
colors.forEach(el => {
colorsLink.push(<li
data-color={el}
key={el}
onClick={this.getColorValue.bind(this)}
ref={el}>
{el}
</li>
);
});
return (
<section>
<ul>
{colorsLink}
</ul>
<button onClick={this.backToPrevious.bind(this)}>back</button>
<button onClick={this.goToNext.bind(this)}>continue</button>
</section>
);
}
}
class ConfirmSingleIcon extends React.Component {
goBack () {
this.props.goBack();
}
confirmCaptionandIcon (event) {
var optionID = event.target.getAttribute("data-option-id"),
name = event.target.getAttribute("data-option-name");
this.props.setOptionID(optionID);
this.props.setIcon(1, name, optionID, false);
}
goNext () {
this.props.goNext();
}
render () {
console.log(this.props.currentState);
var options = [],
that = this;
this.props.iconOptionsList.forEach(function(el){
options.push(<li onClick={that.confirmCaptionandIcon.bind(that)} key={el.option} data-option-name={el.option} data-option-id={el.id}>{el.option}</li>);
});
return (
<div>
<h2>Choose your caption</h2>
<h3>
{this.props.selectedIcon}
</h3>
<ul>
{options}
</ul>
<button onClick={this.goBack.bind(this)} >back</button>
<button onClick={this.goNext.bind(this)} >confirm</button>
</div>
);
}
}
class ConfirmCaption extends React.Component {
handleClick () {
var currentState = this.props.currentState;
this.props.setIcon(currentState.icon_ID, currentState.selectedIcon, currentState.option_ID, true);
this.props.setIconVisiblity(true);
this.props.setIconListVisiblity(false);
}
render () {
console.log(this.props.currentState);
return (
<div>
<p onClick={this.handleClick.bind(this)}>confirm icon and caption</p>
</div>
);
}
}
class ChooseIcon extends React.Component {
constructor(props) {
super(props);
this.state = {
icons: [],
iconList: true,
confirmIcon: false,
confirmCaption: false,
selectedIconOptions: '',
icon_ID: '',
option_ID: '',
selectedIcon: ''
};
this.setOptionID = this.setOptionID.bind(this);
this.setIconVisiblity = this.setIconVisiblity.bind(this);
this.setIconListVisiblity = this.setIconListVisiblity.bind(this);
}
setOptionID (id) {
this.setState({ option_ID: id })
}
setIconVisiblity (onOff) {
this.setState({ confirmIcon: onOff })
}
setIconListVisiblity (onOff) {
this.setState({ iconList: onOff })
}
componentDidMount() {
var url = `http://local.tshirt.net/get-options`;
axios.get(url)
.then(res => {
this.setState({ icons:res.data.icons });
});
}
handleClick (event) {
var iconId = event.target.getAttribute("data-icon-id"),
that = this;
this.state.icons.forEach(function(el){
if(el.id == iconId){
that.setState(
{
confirmIcon: true,
iconList: false,
selectedIcon: el.name,
icon_ID: iconId,
selectedIconOptions: el.option
}
);
}
});
}
goBack () {
this.setState(
{
confirmIcon: false,
iconList: true
}
);
}
goNext () {
this.setState(
{
confirmIcon: false,
iconList: false,
confirmCaption: true
}
);
}
render () {
var icons = [];
this.state.icons.forEach(el => {
icons.push(<li data-icon-id={el.id} onClick={this.handleClick.bind(this)} key={el.name}>{el.name}</li>);
});
return (
<div>
{this.state.iconList ? <IconList icons={icons} /> : ''}
{this.state.confirmIcon ? <ConfirmSingleIcon goBack={this.goBack.bind(this)}
goNext={this.goNext.bind(this)}
setIcon={this.props.setIcon}
selectedIcon={this.state.selectedIcon}
iconOptionsList ={this.state.selectedIconOptions}
setOptionID={this.setOptionID}
currentState={this.state} /> : ''}
{this.state.confirmCaption ? <ConfirmCaption currentState={this.state}
setIcon={this.props.setIcon}
setIconVisiblity={this.setIconVisiblity}
setIconListVisiblity={this.setIconListVisiblity} /> : ''}
</div>
);
}
}
class IconList extends React.Component {
render () {
return (
<div>
<h2>Pick your icon</h2>
<ul>
{this.props.icons}
</ul>
</div>
);
}
}
class Forms extends React.Component {
render () {
var form;
switch(this.props.formID) {
case 1:
form = <FirstName action={this.props.action} actionID={this.props.switchComponent} activeNav={this.props.activeNav} />
break;
case 2:
form = <PickColor displayIconsHolder={this.props.seticonsHolder} color={this.props.colorVal} actionID={this.props.switchComponent} activeNav={this.props.activeNav} />
break;
case 3:
form = <ChooseIcon setIcon={this.props.setOptionA} />
break;
}
return (
<section>
{form}
</section>
);
}
}
export default Forms;
"ChooseIcon" is a component that will get used 3 times therefore everytime I get to it I need to bring its state back as if it was the first time.
Ideally I would need to make this ajax call everytime:
componentDidMount() {
var url = `http://local.tshirt.net/get-options`;
axios.get(url)
.then(res => {
this.setState({ icons:res.data.icons });
});
}
is there a way to manually call componentDidMount perhaps from a parent component?
React handles component lifecycle through key attribute. For example:
<ChooseIcon key={this.props.formID} setIcon={this.props.setOptionA} />
So every time your key (it can be anything you like, but unique) is changed component will unmount and mount again, with this you can easily control componentDidMount callback.
If you are using the ChooseIcon component 3 times inside the same parent component, I would suggest you to do the ajax in componentDidMount of the parent component like this (exaclty how you have in your example, in terms of code)
componentDidMount() {
var url = `http://local.tshirt.net/get-options`;
axios.get(url)
.then(res => {
this.setState({ icons:res.data.icons });
});
}
and then pass this data down to the ChooseIcon component
render() {
return (
//do your stuff
<ChooseIcon icons={this.state.icons}/>
)
}
after this you will only need to set the received props in your ChooseIconcomponent, for that you only need to change one line in it's constructor:
constructor(props) {
super(props);
this.state = {
icons: props.icons, // Changed here!
iconList: true,
confirmIcon: false,
confirmCaption: false,
selectedIconOptions: '',
icon_ID: '',
option_ID: '',
selectedIcon: ''
};
this.setOptionID = this.setOptionID.bind(this);
this.setIconVisiblity = this.setIconVisiblity.bind(this);
this.setIconListVisiblity = this.setIconListVisiblity.bind(this);
}
The parent component can use a ref to call the function directly.
However, trying to force this function feels like a smell. Perhaps lifting the state higher up the component tree would solve this problem. This way, the parent component will tell ChooseIcon what to show, and there will not be a need to call componentDidMount again. Also, I assume the Ajax call can also occur once.

Resources