React - setInterval inside an onChange event
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
add a comment |
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
Just a note:this
poiner insetInterval
doesn't point to the component'sthis
. the first line should be like this:var that=this; this.interval = setInterval(() => that.getData(), 10000);
– Thevs
Nov 21 '18 at 22:34
add a comment |
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
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
javascript reactjs
edited Nov 21 '18 at 17:01
DJ2
asked Nov 21 '18 at 15:52
DJ2DJ2
276113
276113
Just a note:this
poiner insetInterval
doesn't point to the component'sthis
. the first line should be like this:var that=this; this.interval = setInterval(() => that.getData(), 10000);
– Thevs
Nov 21 '18 at 22:34
add a comment |
Just a note:this
poiner insetInterval
doesn't point to the component'sthis
. 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
add a comment |
3 Answers
3
active
oldest
votes
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.
Yes, with the data not all being fetched at once insidecDM
it becomes tricky waiting for the response before re-polling the service. Do you have an example of usingsetTimeout
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
add a comment |
- 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);
}
I'm not sure placing the initial call incDM
in bothonChange
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 byonChange1
then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled byonChange2
, 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 secondonChange
– DJ2
Nov 21 '18 at 16:47
Also the data request are made inside theonChange
methods so I'm not sure whatthis.getData()
insideonChange
in your example is referring to
– DJ2
Nov 21 '18 at 17:13
add a comment |
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.
I'm looking intowebsockets
, not entirely sure where to start with the modification.
– DJ2
Nov 26 '18 at 15:14
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Yes, with the data not all being fetched at once insidecDM
it becomes tricky waiting for the response before re-polling the service. Do you have an example of usingsetTimeout
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
add a comment |
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.
Yes, with the data not all being fetched at once insidecDM
it becomes tricky waiting for the response before re-polling the service. Do you have an example of usingsetTimeout
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
add a comment |
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.
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.
answered Nov 21 '18 at 17:13
Chris HawkesChris Hawkes
6,56833151
6,56833151
Yes, with the data not all being fetched at once insidecDM
it becomes tricky waiting for the response before re-polling the service. Do you have an example of usingsetTimeout
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
add a comment |
Yes, with the data not all being fetched at once insidecDM
it becomes tricky waiting for the response before re-polling the service. Do you have an example of usingsetTimeout
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
add a comment |
- 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);
}
I'm not sure placing the initial call incDM
in bothonChange
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 byonChange1
then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled byonChange2
, 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 secondonChange
– DJ2
Nov 21 '18 at 16:47
Also the data request are made inside theonChange
methods so I'm not sure whatthis.getData()
insideonChange
in your example is referring to
– DJ2
Nov 21 '18 at 17:13
add a comment |
- 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);
}
I'm not sure placing the initial call incDM
in bothonChange
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 byonChange1
then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled byonChange2
, 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 secondonChange
– DJ2
Nov 21 '18 at 16:47
Also the data request are made inside theonChange
methods so I'm not sure whatthis.getData()
insideonChange
in your example is referring to
– DJ2
Nov 21 '18 at 17:13
add a comment |
- 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);
}
- 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);
}
answered Nov 21 '18 at 16:34
Tauqeer HassanTauqeer Hassan
31
31
I'm not sure placing the initial call incDM
in bothonChange
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 byonChange1
then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled byonChange2
, 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 secondonChange
– DJ2
Nov 21 '18 at 16:47
Also the data request are made inside theonChange
methods so I'm not sure whatthis.getData()
insideonChange
in your example is referring to
– DJ2
Nov 21 '18 at 17:13
add a comment |
I'm not sure placing the initial call incDM
in bothonChange
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 byonChange1
then that filters more data for the second dropdown. Upon selecting an option from the second drop down, controlled byonChange2
, 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 secondonChange
– DJ2
Nov 21 '18 at 16:47
Also the data request are made inside theonChange
methods so I'm not sure whatthis.getData()
insideonChange
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
add a comment |
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.
I'm looking intowebsockets
, not entirely sure where to start with the modification.
– DJ2
Nov 26 '18 at 15:14
add a comment |
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.
I'm looking intowebsockets
, not entirely sure where to start with the modification.
– DJ2
Nov 26 '18 at 15:14
add a comment |
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.
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.
edited Nov 21 '18 at 17:20
answered Nov 21 '18 at 17:15
Dan PantryDan Pantry
5,90412149
5,90412149
I'm looking intowebsockets
, not entirely sure where to start with the modification.
– DJ2
Nov 26 '18 at 15:14
add a comment |
I'm looking intowebsockets
, 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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
Just a note:
this
poiner insetInterval
doesn't point to the component'sthis
. the first line should be like this:var that=this; this.interval = setInterval(() => that.getData(), 10000);
– Thevs
Nov 21 '18 at 22:34