I'm trying to control the scroll position of a textarea using a React component's state, but it doesn't move when I call setState()
.
Here's an example where clicking on the link should scroll to the top of the textarea, but it doesn't move. Scrolling with the scroll bar can log the positions, and the field moves. Clicking on the link writes a message to the console, but the scroll position doesn't move. I based this approach on the controlled components described in the ReactJS documentation.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {scrollTop: 0};
this.handleScroll = this.handleScroll.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleScroll() {
let scrollTop = this.refs.content.scrollTop;
console.log(scrollTop);
this.setState({scrollTop: scrollTop});
}
handleClick(e) {
e.preventDefault();
console.log('Clicked.');
this.setState({scrollTop: 0});
}
render() {
let text = 'a\n\nb\n\nc\n\nd\n\ne\n\nf\n\ng';
return <p><textarea
ref="content"
value={text}
rows="10"
cols="30"
scrollTop={this.state.scrollTop}
onScroll={this.handleScroll}/>
<a href="#" onClick={this.handleClick}>
Scroll to top
</a></p>;
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
.as-console-wrapper { max-height: 10% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I can control the scroll position by using the ref and setting its scrollTop
, but I want to control it through the component state or the component properties. (Eventually, I want to synchronize the scrolling of two textareas.) I also tried using the react-scroll-sync
library, but it doesn't work well with table cells.
Here's an example that controls the position using the ref and its scrollTop
:
class App extends React.Component {
constructor(props) {
super(props);
this.handleScroll = this.handleScroll.bind(this);
this.handleClick = this.handleClick.bind(this);
}
handleScroll() {
let scrollTop = this.refs.content.scrollTop;
console.log(scrollTop);
}
handleClick(e) {
e.preventDefault();
console.log('Clicked.');
this.refs.content.scrollTop = 0;
}
render() {
let text = 'a\n\nb\n\nc\n\nd\n\ne\n\nf\n\ng';
return <p><textarea
ref="content"
value={text}
rows="10"
cols="30"
onScroll={this.handleScroll}/>
<a href="#" onClick={this.handleClick}>
Scroll to top
</a></p>;
}
}
ReactDOM.render(
<App/>,
document.getElementById('root')
);
.as-console-wrapper { max-height: 10% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>