我想在一个onChange事件中设置setInterval,就像大多数情况下是在componentDidMount上完成的一样。
我有2个下拉列表,这些下拉列表过滤数据然后呈现表,这些下拉列表由onChange方法控制。最后一个on change方法有一个需要每X#秒重新轮询一次的请求,以从服务器获取更新的信息。但是,这些方法不在cDM之外,因此我不确定如何像以前一样处理setInterval
。
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.
}
如果所有数据都在cDM
中,我通常会将cDM
中的数据请求更改为箭头函数,以避免出现setState
问题,请在{的内部/外部调用该函数{1}}具有以下内容的回调:
setInterval
答案 0 :(得分:1)
SetInterval在重新开始轮询之前不等待AJAX响应。在出现网络问题时,这可能会变得非常容易出错/占用大量内存。
我建议您使用setTimeOut,每次更新时,我都会将一个响应数据放入状态,并在呈现函数内部的状态更改时启动计时器。这样一来,您始终可以确保在返回结果之前,再次重击服务器并阻塞客户端的UI。
答案 1 :(得分:0)
将Interval设置为等于某个状态变量,因此在componentWillUnmount上,您可以访问该间隔并将其删除。
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);
}
答案 2 :(得分:0)
您确实可以将其放置在更新事件处理程序中-事件处理程序不必一定是纯粹的。有一个小问题,即这意味着您的视图不再是国家+道具的功能,但实际上这通常不是问题。
您似乎最担心的是如何对这些数据建模。
执行此操作的一种方法可能是使用更高阶的组件或某种组合,将组件的显示与业务逻辑的实现分开。
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
}
)
}
}
您可以像这样使用此组件:
<WithPolledData intervalMilliseconds={5000} render={YourComponent} />
每当选择下拉选项时, YourComponent
就会调用setOption()
,并且提取将在后台进行。
这是您技术上的方式。我同意@ChrisHawkes的观点,认为像这样使用setInterval可能是一个错误-您至少需要取消进行中的HTTP请求,并且冒着在网络性能差的设备上引起问题的风险。
或者,这里的 push 而不是 pull 模型可能更好-这种情况正是WebSocket设计的目的,不需要太多修改您的代码。