Изменить scrollTop в реакции

Я просто научусь реагировать и хочу добиться функции: оба A, B являются компонентами, если A прокручивается, затем B прокручивается

Ниже приведен мой код

<A onScroll="handleScroll"></A>

//what i write now
handleScroll: function(event){
    var target = event.nativeEvent.target;

    //do something to change scrollTop value
    target.scrollTop += 1;

    // it looks the same as not use react
    document.getElementById(B).scrollTop = target.scrollTop;
}

но на самом деле я хочу, чтобы мой код выглядел как

//what i want
<A scrollTop={this.props.scrollSeed}></A>
<B scrollTop={this.props.scrollSeed}></B>

//...
handleScroll(){
    this.setState({scrollSeed: ++this.state.scrollSeed})
}

он похож на input

<input value="this.props.value"/>
<input value="this.props.value"/>
<input ref='c' onChange={handleChange}>

//...
handleChange: function() {
    // enter some code in c and then render in a and b automatically
}

Другими словами, мне нужен некоторый атрибут, например scrollTop (другой form <input value={}>, потому что <A scrollTop={}> не работает), связывается с некоторым состоянием, поэтому я могу просто использовать setState, и они будут обновляться сами по себе.

Я googled раньше, но не могу найти answser. Я надеюсь, что мой бедный английский не смутит вас.

Ответ 1

Существует ряд шаблонов для достижения этого. Этот образец - это то, что я придумал, чтобы поднять вас.

Сначала создайте класс компонента, который имеет элемент большого размера для эффекта прокрутки. При перетаскивании полосы прокрутки этот компонент вызывает свойство handleScroll React для уведомления своего родительского компонента со значением scrollTop.

var Elem = React.createClass({
    render() {
        return (
            <div ref="elem"
                onScroll={ this.onScroll }
                style={{ width: "100px", height: "100px", overflow: "scroll" }}>
                <div style={{ width: "100%", height: "200%" }}>Hello!</div>
            </div>
        );
    },
    componentDidUpdate() {
        this.refs.elem.scrollTop = this.props.scrollTop;
    },
    onScroll() {
        this.props.handleScroll( this.refs.elem.scrollTop );
    }
});

Родительский компонент, aka wrapper, сохраняет верхнее значение прокрутки в своем состоянии. Его handleScroll передается дочерним компонентам как обратный вызов. Любая прокрутка по дочерним элементам вызывает обратный вызов, устанавливает состояние, приводит к перерисовке и обновляет дочерний компонент.

var Wrapper = React.createClass({
    getInitialState() {
        return {
            scrollTop: 0
        }
    },
    render() {
        return (
            <div>
                <Elem scrollTop={ this.state.scrollTop } handleScroll={ this.handleScroll } />
                <Elem scrollTop={ this.state.scrollTop } handleScroll={ this.handleScroll } />
            </div>
        );
    },
    handleScroll( scrollTop ) {
        this.setState({ scrollTop });
    }
});

И отрисуйте оболочку, предположив существующий <div id="container"></div>.

ReactDOM.render(
    <Wrapper />,
    document.getElementById('container')
);

Ответ 2

this.refs устарела. используйтеactjs.org/docs/refs-and-the-dom.html#creating-refs

import React from 'react';

class SomeComponent extends React.Component {
  constructor(props) {
    super(props);
    this.resultsDiv = React.createRef();
  }

  someFunction(){
     this.resultsDiv.current.scrollTop = 0;
  }

  render() {
    return (
      <div ref={this.resultsDiv} />
    );
  }
}

export default SomeComponent;


Ответ 3

Ответ 2019

Во-первых, исправить:

const resetScrollEffect = ({ element }) => {
  element.current.getScrollableNode().children[0].scrollTop = 0
}

const Table = props => {
  const tableRef = useRef(null)
  useEffect(() => resetScrollEffect({ element: tableRef }), [])
  return (
    <Component>
      <FlatList
        ref={someRef}
      />
    </Component>
  )
}

Во-вторых, небольшое объяснение:

Я знаю, почему вы попали сюда, но я использовал flex-direction: column-reverse для моего FlatList (это список элементов). И мне нужно это свойство для целей z-index. Тем не менее, браузеры устанавливают свою позицию прокрутки до конца для таких элементов (таблиц, чатов и т.д.) - это может быть полезно, но мне это не нужно в моем случае.

Также показан пример с использованием React Hooks, но вы можете использовать более старый, более традиционный способ определения ссылок.

Ответ 4

Здесь обновленная версия ответа Season, включая исполняемый фрагмент. Он использует рекомендуемый метод для создания ссылок.

class Editor extends React.Component {
    constructor(props) {
        super(props);
        this.content = React.createRef();
        this.handleScroll = this.handleScroll.bind(this);
    }

    componentDidUpdate() {
        this.content.current.scrollTop = this.props.scrollTop;
    }
    
    handleScroll() {
        this.props.onScroll( this.content.current.scrollTop );
    }

    render() {
        let text = 'a\n\nb\n\nc\n\nd\n\ne\n\nf\n\ng';
        return <textarea
            ref={this.content}
            value={text}
            rows="10"
            cols="30"
            onScroll={this.handleScroll}/>;
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {scrollTop: 0};
        this.handleScroll = this.handleScroll.bind(this);
    }

    handleScroll(scrollTop) {
        this.setState({scrollTop: scrollTop});
    }

    render() {
        return <table><tbody>
            <tr><th>Foo</th><th>Bar</th></tr>
            <tr>
                <td><Editor
                    scrollTop={this.state.scrollTop}
                    onScroll={this.handleScroll}/></td>
                <td><Editor
                    scrollTop={this.state.scrollTop}
                    onScroll={this.handleScroll}/></td>
            </tr>
        </tbody></table>;
    }
}

ReactDOM.render(
    <App/>,
    document.getElementById('root')
);
<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>