React - setInterval inside an onChange event












0















I want to set setInterval inside an onChange event, like mostly it is done on componentDidMount.



I have 2 dropdowns that filter data and then render a table, the dropdowns are controlled by onChange methods. The last on change method has a request that needs to be re-polled every X # seconds to get updated information from the server. However, these methods are outside of cDM so I'm not sure how to handle the setInterval like I previously have.



cDM() {
//axios call, update state with fetched data
}

onChange1 () {
// uses data from cDM to render the options in a dropdown.
// another axios call based on the selection, fetches data to render more options in subsequent dropdown
}

onChange2 () {
//dropdown 2 use data from onChange1 axios call. After the selection from the dropdown is made, it makes an api call that then renders data to a table.
//Some of this data updates every 5 seconds, so I need to re-poll this service to get updated information from the server.
}


if all the data was in cDM I'd normally change the data requests in cDM to an arrow function to avoid setState issues, call the function inside/outside of the setInterval callback with the following:



componentDidMount() {
this.interval = setInterval(() => this.getData(), 10000);
this.getData();
}

componentWillUnMount() {
clearInterval(this.interval);
}

getData = () => {
//data requests
}









share|improve this question

























  • Just a note: this poiner in setInterval doesn't point to the component's this. the first line should be like this: var that=this; this.interval = setInterval(() => that.getData(), 10000);

    – Thevs
    Nov 21 '18 at 22:34


















0















I want to set setInterval inside an onChange event, like mostly it is done on componentDidMount.



I have 2 dropdowns that filter data and then render a table, the dropdowns are controlled by onChange methods. The last on change method has a request that needs to be re-polled every X # seconds to get updated information from the server. However, these methods are outside of cDM so I'm not sure how to handle the setInterval like I previously have.



cDM() {
//axios call, update state with fetched data
}

onChange1 () {
// uses data from cDM to render the options in a dropdown.
// another axios call based on the selection, fetches data to render more options in subsequent dropdown
}

onChange2 () {
//dropdown 2 use data from onChange1 axios call. After the selection from the dropdown is made, it makes an api call that then renders data to a table.
//Some of this data updates every 5 seconds, so I need to re-poll this service to get updated information from the server.
}


if all the data was in cDM I'd normally change the data requests in cDM to an arrow function to avoid setState issues, call the function inside/outside of the setInterval callback with the following:



componentDidMount() {
this.interval = setInterval(() => this.getData(), 10000);
this.getData();
}

componentWillUnMount() {
clearInterval(this.interval);
}

getData = () => {
//data requests
}









share|improve this question

























  • Just a note: this poiner in setInterval doesn't point to the component's this. the first line should be like this: var that=this; this.interval = setInterval(() => that.getData(), 10000);

    – Thevs
    Nov 21 '18 at 22:34
















0












0








0








I want to set setInterval inside an onChange event, like mostly it is done on componentDidMount.



I have 2 dropdowns that filter data and then render a table, the dropdowns are controlled by onChange methods. The last on change method has a request that needs to be re-polled every X # seconds to get updated information from the server. However, these methods are outside of cDM so I'm not sure how to handle the setInterval like I previously have.



cDM() {
//axios call, update state with fetched data
}

onChange1 () {
// uses data from cDM to render the options in a dropdown.
// another axios call based on the selection, fetches data to render more options in subsequent dropdown
}

onChange2 () {
//dropdown 2 use data from onChange1 axios call. After the selection from the dropdown is made, it makes an api call that then renders data to a table.
//Some of this data updates every 5 seconds, so I need to re-poll this service to get updated information from the server.
}


if all the data was in cDM I'd normally change the data requests in cDM to an arrow function to avoid setState issues, call the function inside/outside of the setInterval callback with the following:



componentDidMount() {
this.interval = setInterval(() => this.getData(), 10000);
this.getData();
}

componentWillUnMount() {
clearInterval(this.interval);
}

getData = () => {
//data requests
}









share|improve this question
















I want to set setInterval inside an onChange event, like mostly it is done on componentDidMount.



I have 2 dropdowns that filter data and then render a table, the dropdowns are controlled by onChange methods. The last on change method has a request that needs to be re-polled every X # seconds to get updated information from the server. However, these methods are outside of cDM so I'm not sure how to handle the setInterval like I previously have.



cDM() {
//axios call, update state with fetched data
}

onChange1 () {
// uses data from cDM to render the options in a dropdown.
// another axios call based on the selection, fetches data to render more options in subsequent dropdown
}

onChange2 () {
//dropdown 2 use data from onChange1 axios call. After the selection from the dropdown is made, it makes an api call that then renders data to a table.
//Some of this data updates every 5 seconds, so I need to re-poll this service to get updated information from the server.
}


if all the data was in cDM I'd normally change the data requests in cDM to an arrow function to avoid setState issues, call the function inside/outside of the setInterval callback with the following:



componentDidMount() {
this.interval = setInterval(() => this.getData(), 10000);
this.getData();
}

componentWillUnMount() {
clearInterval(this.interval);
}

getData = () => {
//data requests
}






javascript reactjs






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 21 '18 at 17:01







DJ2

















asked Nov 21 '18 at 15:52









DJ2DJ2

276113




276113













  • Just a note: this poiner in setInterval doesn't point to the component's this. the first line should be like this: var that=this; this.interval = setInterval(() => that.getData(), 10000);

    – Thevs
    Nov 21 '18 at 22:34





















  • Just a note: this poiner in setInterval doesn't point to the component's this. the first line should be like this: var that=this; this.interval = setInterval(() => that.getData(), 10000);

    – Thevs
    Nov 21 '18 at 22:34



















Just a note: this poiner in setInterval doesn't point to the component's this. the first line should be like this: var that=this; this.interval = setInterval(() => that.getData(), 10000);

– Thevs
Nov 21 '18 at 22:34







Just a note: this poiner in setInterval doesn't point to the component's this. the first line should be like this: var that=this; this.interval = setInterval(() => that.getData(), 10000);

– Thevs
Nov 21 '18 at 22:34














3 Answers
3






active

oldest

votes


















1














SetInterval does not wait for the AJAX response before polling starts over again. This can become extremely buggy/memory intensive in the event of network problems.



I would suggest you use a setTimeOut and every update I would put a piece of response data in state and start the timer upon state changes inside your render function. That way you always ensure you get your result back before pounding the server again and bogging down your client's UI.






share|improve this answer
























  • Yes, with the data not all being fetched at once inside cDM it becomes tricky waiting for the response before re-polling the service. Do you have an example of using setTimeout waiting for results before hitting the server again?

    – DJ2
    Nov 21 '18 at 17:17











  • I can try to provide one soon, but I would say, in your success or error callback on the ajax call, that is where you want to make your subsequent ajax calls and when your finished making them, I would then in that final success callback, fire off my custom component method to update the state.

    – Chris Hawkes
    Nov 21 '18 at 17:22











  • At the same time, while updating the state, I would reset the timer. SetTimeout just takes in a function that will be executed, and the second argument is the amount of time to wait before that function is executed.

    – Chris Hawkes
    Nov 21 '18 at 17:23













  • Here's a codesandbox I made up to elaborate on my issue with a little more detail. codesandbox.io/s/qq0k5wmwj6

    – DJ2
    Nov 21 '18 at 18:56



















0















  • Place the code of componentDidMount body into both onChange events.


  • Set Interval equal to some state variable, so on componentWillUnmount you can access that interval and remove it.



    onChange () {    
    // Change Logic
    ....

    // Interval logic
    clearInterval(this.state.interval); //Clear interval everytime.

    this.state.interval = setInterval(() => this.getData(), 10000);
    this.getData();
    }

    componentWillUnMount() {
    clearInterval(this.state.interval);
    }







share|improve this answer
























  • I'm not sure placing the initial call in cDM in both onChange methods will work as expected. Each onChange is dependent on the previous onChange. cDM gets an initial list of data, select an option which is controlled by onChange1 then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled by onChange2, it renders the corresponding data to a table

    – DJ2
    Nov 21 '18 at 16:40













  • Actually it should work like this: getData() should get values of both dropdowns stored in 2 state variables, and get Data from api on the basis of them. So when you call getDate() on onChange, getData will read values of both dropDowns updated in state Variable and and get data on basis of those 2 values irrespective of which onChange it is called on.

    – Tauqeer Hassan
    Nov 21 '18 at 16:44













  • Only when the data is rendered to the table do I need to re-poll the service I'm requesting in the second onChange

    – DJ2
    Nov 21 '18 at 16:47











  • Also the data request are made inside the onChange methods so I'm not sure what this.getData() inside onChange in your example is referring to

    – DJ2
    Nov 21 '18 at 17:13





















0














You can indeed place this in your update event handler - event handlers do not have to be pure. There is the minor issue that doing this means that your view is no longer a function of state + props, but in reality that's not usually a problem.



It seems your main concern is how you model this data.



One way to do this might be to use a higher order component or some kind of composition, splitting the display of your component from the implementation of the business logic.



interface Props<T> {
intervalMilliseconds: number
render: React.ComponentType<ChildProps<T>>
}

interface State<T> {
// In this example I assume your select option will be some kind of string id, but you may wish to change this.
option: string | undefined
isFetching: boolean
data: T
}

interface ChildProps<T> extends State<T> {
setOption(option: string | undefined): void
}

class WithPolledData<T> extends React.Component<Props<T>, State<T>> {
interval: number

componentDidMount() {
this.setupSubscription()
}

componentDidUnmount() {
this.teardownSubscription()
}

setupSubscription() {
this.interval = setInterval(() => this.fetch(), this.props.intervalMilliseconds)
}

teardownSubscription() {
clearInterval(this.interval)
}

componentDidUpdate(previousProps: Props, previousState: State) {
if (previousProps.intervalMilliseconds !== this.props.intervalMilliseconds) {
this.teardownSubscription()
}
if (previousState.option !== this.state.option && this.state.option !== undefined) {
this.fetch()
}
}

fetch() {
if (this.props.option === undefined) {
// There is nothing to fetch
return
}

// TODO: Fetch the data from the server here with this.props.option as the id
}

setOption = (option: string | undefined) => {
this.setState({ option })
}

render() {
return React.createElement(
this.props.render,
{
...this.state,
setOption: this.setOption
}
)
}
}


You could use this component like so:



<WithPolledData intervalMilliseconds={5000} render={YourComponent} />


YourComponent would call setOption() whenever a drop down option was selected and the fetching would happen in the background.



This is how you would technically do this. I agree with @ChrisHawkes that using setInterval like this is likely a mistake - You would at the very least need to cancel in-flight HTTP requests and you run the risk of causing issues on devices with poor network performance.



Alternatively, a push rather than a pull model may be better here - This scenario is exactly what WebSockets are designed for and it wouldn't require too much modification to your code.






share|improve this answer


























  • I'm looking into websockets, not entirely sure where to start with the modification.

    – DJ2
    Nov 26 '18 at 15:14











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415823%2freact-setinterval-inside-an-onchange-event%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














SetInterval does not wait for the AJAX response before polling starts over again. This can become extremely buggy/memory intensive in the event of network problems.



I would suggest you use a setTimeOut and every update I would put a piece of response data in state and start the timer upon state changes inside your render function. That way you always ensure you get your result back before pounding the server again and bogging down your client's UI.






share|improve this answer
























  • Yes, with the data not all being fetched at once inside cDM it becomes tricky waiting for the response before re-polling the service. Do you have an example of using setTimeout waiting for results before hitting the server again?

    – DJ2
    Nov 21 '18 at 17:17











  • I can try to provide one soon, but I would say, in your success or error callback on the ajax call, that is where you want to make your subsequent ajax calls and when your finished making them, I would then in that final success callback, fire off my custom component method to update the state.

    – Chris Hawkes
    Nov 21 '18 at 17:22











  • At the same time, while updating the state, I would reset the timer. SetTimeout just takes in a function that will be executed, and the second argument is the amount of time to wait before that function is executed.

    – Chris Hawkes
    Nov 21 '18 at 17:23













  • Here's a codesandbox I made up to elaborate on my issue with a little more detail. codesandbox.io/s/qq0k5wmwj6

    – DJ2
    Nov 21 '18 at 18:56
















1














SetInterval does not wait for the AJAX response before polling starts over again. This can become extremely buggy/memory intensive in the event of network problems.



I would suggest you use a setTimeOut and every update I would put a piece of response data in state and start the timer upon state changes inside your render function. That way you always ensure you get your result back before pounding the server again and bogging down your client's UI.






share|improve this answer
























  • Yes, with the data not all being fetched at once inside cDM it becomes tricky waiting for the response before re-polling the service. Do you have an example of using setTimeout waiting for results before hitting the server again?

    – DJ2
    Nov 21 '18 at 17:17











  • I can try to provide one soon, but I would say, in your success or error callback on the ajax call, that is where you want to make your subsequent ajax calls and when your finished making them, I would then in that final success callback, fire off my custom component method to update the state.

    – Chris Hawkes
    Nov 21 '18 at 17:22











  • At the same time, while updating the state, I would reset the timer. SetTimeout just takes in a function that will be executed, and the second argument is the amount of time to wait before that function is executed.

    – Chris Hawkes
    Nov 21 '18 at 17:23













  • Here's a codesandbox I made up to elaborate on my issue with a little more detail. codesandbox.io/s/qq0k5wmwj6

    – DJ2
    Nov 21 '18 at 18:56














1












1








1







SetInterval does not wait for the AJAX response before polling starts over again. This can become extremely buggy/memory intensive in the event of network problems.



I would suggest you use a setTimeOut and every update I would put a piece of response data in state and start the timer upon state changes inside your render function. That way you always ensure you get your result back before pounding the server again and bogging down your client's UI.






share|improve this answer













SetInterval does not wait for the AJAX response before polling starts over again. This can become extremely buggy/memory intensive in the event of network problems.



I would suggest you use a setTimeOut and every update I would put a piece of response data in state and start the timer upon state changes inside your render function. That way you always ensure you get your result back before pounding the server again and bogging down your client's UI.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 '18 at 17:13









Chris HawkesChris Hawkes

6,56833151




6,56833151













  • Yes, with the data not all being fetched at once inside cDM it becomes tricky waiting for the response before re-polling the service. Do you have an example of using setTimeout waiting for results before hitting the server again?

    – DJ2
    Nov 21 '18 at 17:17











  • I can try to provide one soon, but I would say, in your success or error callback on the ajax call, that is where you want to make your subsequent ajax calls and when your finished making them, I would then in that final success callback, fire off my custom component method to update the state.

    – Chris Hawkes
    Nov 21 '18 at 17:22











  • At the same time, while updating the state, I would reset the timer. SetTimeout just takes in a function that will be executed, and the second argument is the amount of time to wait before that function is executed.

    – Chris Hawkes
    Nov 21 '18 at 17:23













  • Here's a codesandbox I made up to elaborate on my issue with a little more detail. codesandbox.io/s/qq0k5wmwj6

    – DJ2
    Nov 21 '18 at 18:56



















  • Yes, with the data not all being fetched at once inside cDM it becomes tricky waiting for the response before re-polling the service. Do you have an example of using setTimeout waiting for results before hitting the server again?

    – DJ2
    Nov 21 '18 at 17:17











  • I can try to provide one soon, but I would say, in your success or error callback on the ajax call, that is where you want to make your subsequent ajax calls and when your finished making them, I would then in that final success callback, fire off my custom component method to update the state.

    – Chris Hawkes
    Nov 21 '18 at 17:22











  • At the same time, while updating the state, I would reset the timer. SetTimeout just takes in a function that will be executed, and the second argument is the amount of time to wait before that function is executed.

    – Chris Hawkes
    Nov 21 '18 at 17:23













  • Here's a codesandbox I made up to elaborate on my issue with a little more detail. codesandbox.io/s/qq0k5wmwj6

    – DJ2
    Nov 21 '18 at 18:56

















Yes, with the data not all being fetched at once inside cDM it becomes tricky waiting for the response before re-polling the service. Do you have an example of using setTimeout waiting for results before hitting the server again?

– DJ2
Nov 21 '18 at 17:17





Yes, with the data not all being fetched at once inside cDM it becomes tricky waiting for the response before re-polling the service. Do you have an example of using setTimeout waiting for results before hitting the server again?

– DJ2
Nov 21 '18 at 17:17













I can try to provide one soon, but I would say, in your success or error callback on the ajax call, that is where you want to make your subsequent ajax calls and when your finished making them, I would then in that final success callback, fire off my custom component method to update the state.

– Chris Hawkes
Nov 21 '18 at 17:22





I can try to provide one soon, but I would say, in your success or error callback on the ajax call, that is where you want to make your subsequent ajax calls and when your finished making them, I would then in that final success callback, fire off my custom component method to update the state.

– Chris Hawkes
Nov 21 '18 at 17:22













At the same time, while updating the state, I would reset the timer. SetTimeout just takes in a function that will be executed, and the second argument is the amount of time to wait before that function is executed.

– Chris Hawkes
Nov 21 '18 at 17:23







At the same time, while updating the state, I would reset the timer. SetTimeout just takes in a function that will be executed, and the second argument is the amount of time to wait before that function is executed.

– Chris Hawkes
Nov 21 '18 at 17:23















Here's a codesandbox I made up to elaborate on my issue with a little more detail. codesandbox.io/s/qq0k5wmwj6

– DJ2
Nov 21 '18 at 18:56





Here's a codesandbox I made up to elaborate on my issue with a little more detail. codesandbox.io/s/qq0k5wmwj6

– DJ2
Nov 21 '18 at 18:56













0















  • Place the code of componentDidMount body into both onChange events.


  • Set Interval equal to some state variable, so on componentWillUnmount you can access that interval and remove it.



    onChange () {    
    // Change Logic
    ....

    // Interval logic
    clearInterval(this.state.interval); //Clear interval everytime.

    this.state.interval = setInterval(() => this.getData(), 10000);
    this.getData();
    }

    componentWillUnMount() {
    clearInterval(this.state.interval);
    }







share|improve this answer
























  • I'm not sure placing the initial call in cDM in both onChange methods will work as expected. Each onChange is dependent on the previous onChange. cDM gets an initial list of data, select an option which is controlled by onChange1 then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled by onChange2, it renders the corresponding data to a table

    – DJ2
    Nov 21 '18 at 16:40













  • Actually it should work like this: getData() should get values of both dropdowns stored in 2 state variables, and get Data from api on the basis of them. So when you call getDate() on onChange, getData will read values of both dropDowns updated in state Variable and and get data on basis of those 2 values irrespective of which onChange it is called on.

    – Tauqeer Hassan
    Nov 21 '18 at 16:44













  • Only when the data is rendered to the table do I need to re-poll the service I'm requesting in the second onChange

    – DJ2
    Nov 21 '18 at 16:47











  • Also the data request are made inside the onChange methods so I'm not sure what this.getData() inside onChange in your example is referring to

    – DJ2
    Nov 21 '18 at 17:13


















0















  • Place the code of componentDidMount body into both onChange events.


  • Set Interval equal to some state variable, so on componentWillUnmount you can access that interval and remove it.



    onChange () {    
    // Change Logic
    ....

    // Interval logic
    clearInterval(this.state.interval); //Clear interval everytime.

    this.state.interval = setInterval(() => this.getData(), 10000);
    this.getData();
    }

    componentWillUnMount() {
    clearInterval(this.state.interval);
    }







share|improve this answer
























  • I'm not sure placing the initial call in cDM in both onChange methods will work as expected. Each onChange is dependent on the previous onChange. cDM gets an initial list of data, select an option which is controlled by onChange1 then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled by onChange2, it renders the corresponding data to a table

    – DJ2
    Nov 21 '18 at 16:40













  • Actually it should work like this: getData() should get values of both dropdowns stored in 2 state variables, and get Data from api on the basis of them. So when you call getDate() on onChange, getData will read values of both dropDowns updated in state Variable and and get data on basis of those 2 values irrespective of which onChange it is called on.

    – Tauqeer Hassan
    Nov 21 '18 at 16:44













  • Only when the data is rendered to the table do I need to re-poll the service I'm requesting in the second onChange

    – DJ2
    Nov 21 '18 at 16:47











  • Also the data request are made inside the onChange methods so I'm not sure what this.getData() inside onChange in your example is referring to

    – DJ2
    Nov 21 '18 at 17:13
















0












0








0








  • Place the code of componentDidMount body into both onChange events.


  • Set Interval equal to some state variable, so on componentWillUnmount you can access that interval and remove it.



    onChange () {    
    // Change Logic
    ....

    // Interval logic
    clearInterval(this.state.interval); //Clear interval everytime.

    this.state.interval = setInterval(() => this.getData(), 10000);
    this.getData();
    }

    componentWillUnMount() {
    clearInterval(this.state.interval);
    }







share|improve this answer














  • Place the code of componentDidMount body into both onChange events.


  • Set Interval equal to some state variable, so on componentWillUnmount you can access that interval and remove it.



    onChange () {    
    // Change Logic
    ....

    // Interval logic
    clearInterval(this.state.interval); //Clear interval everytime.

    this.state.interval = setInterval(() => this.getData(), 10000);
    this.getData();
    }

    componentWillUnMount() {
    clearInterval(this.state.interval);
    }








share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 '18 at 16:34









Tauqeer HassanTauqeer Hassan

31




31













  • I'm not sure placing the initial call in cDM in both onChange methods will work as expected. Each onChange is dependent on the previous onChange. cDM gets an initial list of data, select an option which is controlled by onChange1 then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled by onChange2, it renders the corresponding data to a table

    – DJ2
    Nov 21 '18 at 16:40













  • Actually it should work like this: getData() should get values of both dropdowns stored in 2 state variables, and get Data from api on the basis of them. So when you call getDate() on onChange, getData will read values of both dropDowns updated in state Variable and and get data on basis of those 2 values irrespective of which onChange it is called on.

    – Tauqeer Hassan
    Nov 21 '18 at 16:44













  • Only when the data is rendered to the table do I need to re-poll the service I'm requesting in the second onChange

    – DJ2
    Nov 21 '18 at 16:47











  • Also the data request are made inside the onChange methods so I'm not sure what this.getData() inside onChange in your example is referring to

    – DJ2
    Nov 21 '18 at 17:13





















  • I'm not sure placing the initial call in cDM in both onChange methods will work as expected. Each onChange is dependent on the previous onChange. cDM gets an initial list of data, select an option which is controlled by onChange1 then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled by onChange2, it renders the corresponding data to a table

    – DJ2
    Nov 21 '18 at 16:40













  • Actually it should work like this: getData() should get values of both dropdowns stored in 2 state variables, and get Data from api on the basis of them. So when you call getDate() on onChange, getData will read values of both dropDowns updated in state Variable and and get data on basis of those 2 values irrespective of which onChange it is called on.

    – Tauqeer Hassan
    Nov 21 '18 at 16:44













  • Only when the data is rendered to the table do I need to re-poll the service I'm requesting in the second onChange

    – DJ2
    Nov 21 '18 at 16:47











  • Also the data request are made inside the onChange methods so I'm not sure what this.getData() inside onChange in your example is referring to

    – DJ2
    Nov 21 '18 at 17:13



















I'm not sure placing the initial call in cDM in both onChange methods will work as expected. Each onChange is dependent on the previous onChange. cDM gets an initial list of data, select an option which is controlled by onChange1 then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled by onChange2, it renders the corresponding data to a table

– DJ2
Nov 21 '18 at 16:40







I'm not sure placing the initial call in cDM in both onChange methods will work as expected. Each onChange is dependent on the previous onChange. cDM gets an initial list of data, select an option which is controlled by onChange1 then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled by onChange2, it renders the corresponding data to a table

– DJ2
Nov 21 '18 at 16:40















Actually it should work like this: getData() should get values of both dropdowns stored in 2 state variables, and get Data from api on the basis of them. So when you call getDate() on onChange, getData will read values of both dropDowns updated in state Variable and and get data on basis of those 2 values irrespective of which onChange it is called on.

– Tauqeer Hassan
Nov 21 '18 at 16:44







Actually it should work like this: getData() should get values of both dropdowns stored in 2 state variables, and get Data from api on the basis of them. So when you call getDate() on onChange, getData will read values of both dropDowns updated in state Variable and and get data on basis of those 2 values irrespective of which onChange it is called on.

– Tauqeer Hassan
Nov 21 '18 at 16:44















Only when the data is rendered to the table do I need to re-poll the service I'm requesting in the second onChange

– DJ2
Nov 21 '18 at 16:47





Only when the data is rendered to the table do I need to re-poll the service I'm requesting in the second onChange

– DJ2
Nov 21 '18 at 16:47













Also the data request are made inside the onChange methods so I'm not sure what this.getData() inside onChange in your example is referring to

– DJ2
Nov 21 '18 at 17:13







Also the data request are made inside the onChange methods so I'm not sure what this.getData() inside onChange in your example is referring to

– DJ2
Nov 21 '18 at 17:13













0














You can indeed place this in your update event handler - event handlers do not have to be pure. There is the minor issue that doing this means that your view is no longer a function of state + props, but in reality that's not usually a problem.



It seems your main concern is how you model this data.



One way to do this might be to use a higher order component or some kind of composition, splitting the display of your component from the implementation of the business logic.



interface Props<T> {
intervalMilliseconds: number
render: React.ComponentType<ChildProps<T>>
}

interface State<T> {
// In this example I assume your select option will be some kind of string id, but you may wish to change this.
option: string | undefined
isFetching: boolean
data: T
}

interface ChildProps<T> extends State<T> {
setOption(option: string | undefined): void
}

class WithPolledData<T> extends React.Component<Props<T>, State<T>> {
interval: number

componentDidMount() {
this.setupSubscription()
}

componentDidUnmount() {
this.teardownSubscription()
}

setupSubscription() {
this.interval = setInterval(() => this.fetch(), this.props.intervalMilliseconds)
}

teardownSubscription() {
clearInterval(this.interval)
}

componentDidUpdate(previousProps: Props, previousState: State) {
if (previousProps.intervalMilliseconds !== this.props.intervalMilliseconds) {
this.teardownSubscription()
}
if (previousState.option !== this.state.option && this.state.option !== undefined) {
this.fetch()
}
}

fetch() {
if (this.props.option === undefined) {
// There is nothing to fetch
return
}

// TODO: Fetch the data from the server here with this.props.option as the id
}

setOption = (option: string | undefined) => {
this.setState({ option })
}

render() {
return React.createElement(
this.props.render,
{
...this.state,
setOption: this.setOption
}
)
}
}


You could use this component like so:



<WithPolledData intervalMilliseconds={5000} render={YourComponent} />


YourComponent would call setOption() whenever a drop down option was selected and the fetching would happen in the background.



This is how you would technically do this. I agree with @ChrisHawkes that using setInterval like this is likely a mistake - You would at the very least need to cancel in-flight HTTP requests and you run the risk of causing issues on devices with poor network performance.



Alternatively, a push rather than a pull model may be better here - This scenario is exactly what WebSockets are designed for and it wouldn't require too much modification to your code.






share|improve this answer


























  • I'm looking into websockets, not entirely sure where to start with the modification.

    – DJ2
    Nov 26 '18 at 15:14
















0














You can indeed place this in your update event handler - event handlers do not have to be pure. There is the minor issue that doing this means that your view is no longer a function of state + props, but in reality that's not usually a problem.



It seems your main concern is how you model this data.



One way to do this might be to use a higher order component or some kind of composition, splitting the display of your component from the implementation of the business logic.



interface Props<T> {
intervalMilliseconds: number
render: React.ComponentType<ChildProps<T>>
}

interface State<T> {
// In this example I assume your select option will be some kind of string id, but you may wish to change this.
option: string | undefined
isFetching: boolean
data: T
}

interface ChildProps<T> extends State<T> {
setOption(option: string | undefined): void
}

class WithPolledData<T> extends React.Component<Props<T>, State<T>> {
interval: number

componentDidMount() {
this.setupSubscription()
}

componentDidUnmount() {
this.teardownSubscription()
}

setupSubscription() {
this.interval = setInterval(() => this.fetch(), this.props.intervalMilliseconds)
}

teardownSubscription() {
clearInterval(this.interval)
}

componentDidUpdate(previousProps: Props, previousState: State) {
if (previousProps.intervalMilliseconds !== this.props.intervalMilliseconds) {
this.teardownSubscription()
}
if (previousState.option !== this.state.option && this.state.option !== undefined) {
this.fetch()
}
}

fetch() {
if (this.props.option === undefined) {
// There is nothing to fetch
return
}

// TODO: Fetch the data from the server here with this.props.option as the id
}

setOption = (option: string | undefined) => {
this.setState({ option })
}

render() {
return React.createElement(
this.props.render,
{
...this.state,
setOption: this.setOption
}
)
}
}


You could use this component like so:



<WithPolledData intervalMilliseconds={5000} render={YourComponent} />


YourComponent would call setOption() whenever a drop down option was selected and the fetching would happen in the background.



This is how you would technically do this. I agree with @ChrisHawkes that using setInterval like this is likely a mistake - You would at the very least need to cancel in-flight HTTP requests and you run the risk of causing issues on devices with poor network performance.



Alternatively, a push rather than a pull model may be better here - This scenario is exactly what WebSockets are designed for and it wouldn't require too much modification to your code.






share|improve this answer


























  • I'm looking into websockets, not entirely sure where to start with the modification.

    – DJ2
    Nov 26 '18 at 15:14














0












0








0







You can indeed place this in your update event handler - event handlers do not have to be pure. There is the minor issue that doing this means that your view is no longer a function of state + props, but in reality that's not usually a problem.



It seems your main concern is how you model this data.



One way to do this might be to use a higher order component or some kind of composition, splitting the display of your component from the implementation of the business logic.



interface Props<T> {
intervalMilliseconds: number
render: React.ComponentType<ChildProps<T>>
}

interface State<T> {
// In this example I assume your select option will be some kind of string id, but you may wish to change this.
option: string | undefined
isFetching: boolean
data: T
}

interface ChildProps<T> extends State<T> {
setOption(option: string | undefined): void
}

class WithPolledData<T> extends React.Component<Props<T>, State<T>> {
interval: number

componentDidMount() {
this.setupSubscription()
}

componentDidUnmount() {
this.teardownSubscription()
}

setupSubscription() {
this.interval = setInterval(() => this.fetch(), this.props.intervalMilliseconds)
}

teardownSubscription() {
clearInterval(this.interval)
}

componentDidUpdate(previousProps: Props, previousState: State) {
if (previousProps.intervalMilliseconds !== this.props.intervalMilliseconds) {
this.teardownSubscription()
}
if (previousState.option !== this.state.option && this.state.option !== undefined) {
this.fetch()
}
}

fetch() {
if (this.props.option === undefined) {
// There is nothing to fetch
return
}

// TODO: Fetch the data from the server here with this.props.option as the id
}

setOption = (option: string | undefined) => {
this.setState({ option })
}

render() {
return React.createElement(
this.props.render,
{
...this.state,
setOption: this.setOption
}
)
}
}


You could use this component like so:



<WithPolledData intervalMilliseconds={5000} render={YourComponent} />


YourComponent would call setOption() whenever a drop down option was selected and the fetching would happen in the background.



This is how you would technically do this. I agree with @ChrisHawkes that using setInterval like this is likely a mistake - You would at the very least need to cancel in-flight HTTP requests and you run the risk of causing issues on devices with poor network performance.



Alternatively, a push rather than a pull model may be better here - This scenario is exactly what WebSockets are designed for and it wouldn't require too much modification to your code.






share|improve this answer















You can indeed place this in your update event handler - event handlers do not have to be pure. There is the minor issue that doing this means that your view is no longer a function of state + props, but in reality that's not usually a problem.



It seems your main concern is how you model this data.



One way to do this might be to use a higher order component or some kind of composition, splitting the display of your component from the implementation of the business logic.



interface Props<T> {
intervalMilliseconds: number
render: React.ComponentType<ChildProps<T>>
}

interface State<T> {
// In this example I assume your select option will be some kind of string id, but you may wish to change this.
option: string | undefined
isFetching: boolean
data: T
}

interface ChildProps<T> extends State<T> {
setOption(option: string | undefined): void
}

class WithPolledData<T> extends React.Component<Props<T>, State<T>> {
interval: number

componentDidMount() {
this.setupSubscription()
}

componentDidUnmount() {
this.teardownSubscription()
}

setupSubscription() {
this.interval = setInterval(() => this.fetch(), this.props.intervalMilliseconds)
}

teardownSubscription() {
clearInterval(this.interval)
}

componentDidUpdate(previousProps: Props, previousState: State) {
if (previousProps.intervalMilliseconds !== this.props.intervalMilliseconds) {
this.teardownSubscription()
}
if (previousState.option !== this.state.option && this.state.option !== undefined) {
this.fetch()
}
}

fetch() {
if (this.props.option === undefined) {
// There is nothing to fetch
return
}

// TODO: Fetch the data from the server here with this.props.option as the id
}

setOption = (option: string | undefined) => {
this.setState({ option })
}

render() {
return React.createElement(
this.props.render,
{
...this.state,
setOption: this.setOption
}
)
}
}


You could use this component like so:



<WithPolledData intervalMilliseconds={5000} render={YourComponent} />


YourComponent would call setOption() whenever a drop down option was selected and the fetching would happen in the background.



This is how you would technically do this. I agree with @ChrisHawkes that using setInterval like this is likely a mistake - You would at the very least need to cancel in-flight HTTP requests and you run the risk of causing issues on devices with poor network performance.



Alternatively, a push rather than a pull model may be better here - This scenario is exactly what WebSockets are designed for and it wouldn't require too much modification to your code.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 21 '18 at 17:20

























answered Nov 21 '18 at 17:15









Dan PantryDan Pantry

5,90412149




5,90412149













  • I'm looking into websockets, not entirely sure where to start with the modification.

    – DJ2
    Nov 26 '18 at 15:14



















  • I'm looking into websockets, not entirely sure where to start with the modification.

    – DJ2
    Nov 26 '18 at 15:14

















I'm looking into websockets, not entirely sure where to start with the modification.

– DJ2
Nov 26 '18 at 15:14





I'm looking into websockets, not entirely sure where to start with the modification.

– DJ2
Nov 26 '18 at 15:14


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53415823%2freact-setinterval-inside-an-onchange-event%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

If I really need a card on my start hand, how many mulligans make sense? [duplicate]

Alcedinidae

Can an atomic nucleus contain both particles and antiparticles? [duplicate]