Reputation: 591
https://codepen.io/Fadeoc/pen/KvVExP?editors=1111
This is my code in 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"));
I am trying to build a list that auto scroll to above after render, if the list height is higher than the container. Update list members via websocket data, after every websocket message, update the list member, and compare the height again to determain whether to auto scroll or not.
I am new to React, so all come to my mind is set a "style" state, calculate the offset in components, and re-set the state, so react will render again.
It works fine till I found two problems.
First problem is I want to update this list via websocket data, I think "it will re-render as the props has changed thus also the state has changed", but it mess with the second problem, it seems the way I made this auto-scroll part wrong.
As you know, the component normally render once via every state, but in this situation, I probably set the state too much times, every 20 ms, I am worrying about the performance.
And after every push from the websocket server, the list does change into a new one, but it stop auto scroll.
To sum up:
1 Is "set the state every 20 ms to perform a auto-scroll" bad?
2 why it stops auto-scroll after updates via props? should I use componentDidUpdate? But this lifecycle method mess with the auto-scroll because it run to frequently.
Upvotes: 1
Views: 421
Reputation: 2732
I am unsure whether auto-scroll every 20ms is good or bad, but in my opinion, scroll should happen only when more items are added into your list. Not sure how often the web socket fetch is triggered (I am not well versed with web socket).
I guess you want to auto scroll whenever the props are changed. For this, the ideal component event is ComponentWillReceiveProps
which has nextProps (new props per se). You can compare the current props with next props to see if there is any change, if yes then initiate the scrolling thing.
Example:
ComponentWillReceiveProps(nextProps){
if (this.props.myName !== nextProps.myName) {
// do the code
}
}
Upvotes: 1