React-onChange事件中的setInterval

时间:2018-11-21 15:52:41

标签: javascript reactjs

我想在一个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

3 个答案:

答案 0 :(得分:1)

SetInterval在重新开始轮询之前不等待AJAX​​响应。在出现网络问题时,这可能会变得非常容易出错/占用大量内存。

我建议您使用setTimeOut,每次更新时,我都会将一个响应数据放入状态,并在呈现函数内部的状态更改时启动计时器。这样一来,您始终可以确保在返回结果之前,再次重击服务器并阻塞客户端的UI。

答案 1 :(得分:0)

  • 将componentDidMount主体的代码放入两个onChange事件中。
  • 将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设计的目的,不需要太多修改您的代码。