如何在componentDidMount之后运行setInterval并在props更新后重新运行它?

时间:2017-07-31 03:55:53

标签: reactjs

https://codepen.io/Fadeoc/pen/KvVExP?editors=1111

这是我在Codepen中的代码。

let jsonData = {
  value: [1,2,3,4,5,6,7,8,9,10]
}

class Father extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: jsonData,//data from websocket
    }
  }
  render() {
    const arr = this.state.data.value;
    return (
      <Child arr={arr} />
    );
  }
}

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      style: null,
      arr: this.props.arr
    };
  }

  getNodePositionBottom(ref) {
    const nodeY = ReactDOM.findDOMNode(ref).getBoundingClientRect().bottom;
    return nodeY;
  }

  getNodePositionTop(ref) {
    const nodeY = ReactDOM.findDOMNode(ref).getBoundingClientRect().top;
    return nodeY;
  }

  componentDidMount() {
    const divBottom = this.getNodePositionBottom(this.div);
    const divTop = this.getNodePositionTop(this.div);
    const height = divBottom - divTop;

    const ulBottom = this.getNodePositionBottom(this.ul);
    const ulTop = this.getNodePositionTop(this.ul);
    const heightUL = ulBottom - ulTop;

    if (ulBottom > divBottom) {
      this.scrollingTop = setInterval(
        function(){
          this.offsetY = this.offsetY || 0;
          if (ulBottom > divTop && this.offsetY + heightUL!== 0) {
            this.offsetY -= 1;
            this.setState({
              style: {top: + this.offsetY + "px"}
            });
          } else {
            this.setState({
              style: {top: height + "px"}
            });
            this.offsetY = height;
          }
        }.bind(this),
        20
      );
    }
  }

  render() {
    const arr = this.state.arr;
    let arrList = arr.map((name, i) => <li key={i} className="list">{name}</li>);
    return (
      <div ref={(div) => {this.div = div}} className="father">
        <ul ref={(ul) => {this.ul = ul}} className="child" style={this.state.style}>
          {arrList}
        </ul>
      </div>
    );
  }
}

ReactDOM.render(<Father />, document.getElementById("app"));

如果列表高度高于容器,我正在尝试构建一个在渲染后自动滚动到上面的列表。通过websocket数据更新列表成员,在每个websocket消息之后,更新列表成员,并再次比较高度以确定是否自动滚动。

我是React的新手,所以我想到的一切都是&#34;风格&#34; state,计算组件中的偏移量,并重新设置状态,因此react将再次渲染。

它工作正常,直到我发现两个问题。

第一个问题是我想通过websocket数据更新这个列表,我认为&#34;它会在道具发生变化的情况下重新渲染,因此状态也发生了变化,但是第二个问题很糟糕,这似乎是我使这个自动滚动部分错误的方式。

如你所知,组件通常会在每个状态下渲染一次,但在这种情况下,我可能会设置状态太多次,每20毫秒,我担心性能。

每次从websocket服务器推送后,列表都会变为新列表,但会停止自动滚动。

总结一下:

1是&#34;每20毫秒设置一次状态以执行自动滚动&#34;坏?

2为什么它会在通过道具更新后停止自动滚动?我应该使用componentDidUpdate吗?但是这个生命周期方法会因为它经常运行而混乱自动滚动。

1 个答案:

答案 0 :(得分:1)

  1. 我不确定每20ms的自动滚动是好还是坏,但在我看来,只有在列表中添加了更多项目时才会滚动。不确定触发Web套接字的频率是多少(我不熟悉Web套接字)。

  2. 我想你想在改变道具时自动滚动。为此,理想的组件事件是ComponentWillReceiveProps,其中包含nextProps(新道具本身)。您可以将当前道具与下一个道具进行比较以查看是否有任何更改,如果是,则启动滚动操作。

  3. 示例:

    ComponentWillReceiveProps(nextProps){
      if (this.props.myName !== nextProps.myName) {
        // do the code
      }
    }