Reputation: 755
I trigger an API call to elasticsearch with onChange
so that I can prompt a list for autocomplete.
To ensure that my store was updated before rerender I added componentDidMount so that I am not one tick behind. But getting to the point needs code, so:
constructor(props) {
super(props)
this.state = {
inputValue: '',
options: []
};
this.props = {
inputValue: '',
options: []
};
this._onChange = this._onChange.bind(this);
}
componentDidMount() {
CodeStore.addChangeListener(this._onChange);
}
_onChange(event) {
if (this.state.inputValue && !event) {
var enteredChars = this.state.inputValue;
console.log('NO EVENT!');
} else if (event.target.value) {
console.log('EVENT!');
var enteredChars = event.target.value;
this.setState({inputValue: enteredChars});
}
CodeService.nextCode(enteredChars);
}
As you can see I added some log events just to get sure my condition is doing right. I read about that setState
provokes a rerender so it is inside the condition but that didn't had stopped the loop . And the console log confirms the condition switch. But having the setState
inside my condition brakes the functionality and I do not get a list.
Here is my log:
0
Home.jsx:48 EVENT!
Home.jsx:50 0
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
10OptionTemplate.jsx:15 render-list
CodeService.js:27 request
CodeActions.js:10 dispatch
CodeStore.js:22 store
Home.jsx:43 1
Home.jsx:46 NO EVENT!
The infinity loop does not hurt the performance anyhow. I think because of componentWillUnmount
but the massive amount of API calls have to be avoided. Hope this is enough information for any evidence.
Upvotes: 3
Views: 4769
Reputation: 14101
Looks like the infinite loop is caused by the following pattern:
Steps to take to fix:
Then your code could look something like this:
constructor(props) {
super(props)
this.state = {
options: []
};
// removed the this.props bit: props should not be updated inside component
this._onChangeUser = this._onChangeUser.bind(this);
this._onChangeStore = this._onChangeStore.bind(this);
}
componentDidMount() {
CodeStore.addChangeListener(this._onChange); // this is OK
}
_onChangeUser(event) {
console.log('EVENT!');
var enteredChars = event.target.value;
CodeService.nextCode(enteredChars);
// No need to update state here - go to sleep until store changes
}
_onChangeStore() {
var newList = getListFromStore(); // your own function to get list from store
this.setState({ options: newList}); // update state here
}
Not sure what you meant by 'one tick behind', or what could have caused it, but cleaning up endless loop is a good place to start ;)
PS: Code above is sketch only, may have typo's.
Upvotes: 2
Reputation: 4945
It looks like you are using _onChange for both your input event and store listener. They need separate methods.
Upvotes: 1