I have a simple component like this:
var component = React.createClass({
render: function(){
if (this.props.isCollapsed){
return this.renderCollapsed();
}
return this.renderActive()
},
renderActive: function(){
return (
<div>
...
</div>
);
},
renderCollapsed: function(){
return (
<div>
...
</div>
);
},
});
Basically, when the property changes, the component will either show active state or collapse state.
What I am thinking is, when the property change happens, i.e. active->collapse, or the other way around, I want the old view "shrink" or "expand" smoothly to show the new view. For example, if it is active -> collapse, I want the active UI to shrink to the size of collapse UI, and show it smoothly.
I am not sure how to achieve this effect. Please share some ideas. Thanks!
Here is a minimal working example:
const collapsible = ({active, toggle}) =>
<div>
<button type="button" onClick={toggle}>Toggle</button>
<div className={'collapsible' + (active? ' active': '')}>
text
</div>
</div>
const component = React.createClass({
getInitialState() {
return {active: false}
},
toggle() {
this.setState({active: !this.state.active})
},
render() {
return collapsible({active: this.state.active, toggle: this.toggle})
}
})
ReactDOM.render(React.createElement(component), document.querySelector('#root'))
.collapsible {
height: 1.5rem;
transition: height 0.25s linear;
background: #333;
border-radius: 0.25rem
}
.collapsible.active {
height: 7rem
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="root"></div>
The view can be "shrink" or "expand" smoothly by CSS transition, which is triggered by changing CSS properties.
To control CSS properties with React, we can reflect state changes to property values or className in render().
In this example, .active class affects height value, and is controlled by state.active. The class is toggled by React in response to state changes, and triggers CSS transition.
For smoother transitions, See this article.
Rather than conditionally render two different end states of a
component, you could instead toggle the class on the same
component. You could have active and collapsed classes as follows:
For example:
.active{
-webkit-transition: -webkit-transform .5s linear; // transition of
// 0.5 of a second
height: 200px;
}
.collapsed{
height: 0px;
}
Check out this resource for examples
The standard way is to use CSSTransitionGroup from react-transition-group, which is quite easy. Wrap the component with the CSSTransitionGroup and set timeouts on enter and leave, like this:
<CSSTransitionGroup
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{items}
</CSSTransitionGroup>
From the v1-stable docs:
"In this component, when a new item is added to CSSTransitionGroup it
will get the example-enter CSS class and the example-enter-active CSS
class added in the next tick."
Add styling for the CSS classes to get the correct animation.
There's also pretty good explanation in React docs, check it out.
There are third-party components for animation as well.
One more approach to this situation might be changing state after animation completes. The benefits of it is that you can apply not only transitions but whatever actions you want (js animations, smil, etc ..), main thing is not to forget to call an end callback;)
Here is working example CodePen
And here is the code example:
const runTransition = (node, {property = 'opacity', from, to, duration = 600, post = ''}, end) => {
const dif = to - from;
const start = Date.now();
const animate = ()=>{
const step = Date.now() - start;
if (step >= duration) {
node.style[property] = to + post;
return typeof end == 'function' && end();
}
const val =from + (dif * (step/duration));
node.style[property] = val + post;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
}
class Comp extends React.Component {
constructor(props) {
super(props);
this.state = {
isCollapsed: false
}
this.onclick = (e)=>{
this.hide(e.currentTarget,()=>{
this.setState({isCollapsed: !this.state.isCollapsed})
});
};
this.refF = (n)=>{
n && this.show(n);
};
}
render() {
if (this.state.isCollapsed){
return this.renderCollapsed();
}
return this.renderActive()
}
renderCollapsed() {
return (
<div
key='b'
style={{opacity: 0}}
ref={this.refF}
className={`b`}
onClick={this.onclick}>
<h2>I'm Collapsed</h2>
</div>
)
}
renderActive() {
return (
<div
key='a'
style={{opacity: 0}}
ref={this.refF}
className={`a`}
onClick={this.onclick}>
<h2>I'm Active</h2>
</div>
)
}
show(node, cb) {
runTransition(node, {from: 0, to: 1}, cb);
}
hide(node, cb) {
runTransition(node, {from: 1, to: 0}, cb);
}
}
ReactDOM.render(<Comp />, document.getElementById('content'));
And for sure, for this approach to work your only opportunity is to relay on state, instead of props of Component, which you can always set in componentWillReceiveProps method if you have to deal with them.
Updated
Codepen link updated with more clear example which is showing benefits of this approach. Transition changed to javascript animation, without relying on transitionend event.
As you want to render two different component for each of active and collapsed, wrap them in a div that controls the height with the help of CSS.
render: function(){
var cls = this.props.isCollapsed() ? 'collapsed' : 'expanded';
return(
<div className={cls + ' wrapper'}>
{
this.props.isCollapsed() ?
this.renderCollapsed() :
this.renderActive()
}
</div>
);
}
and in your CSS:
.wrapper{
transition: transform .5s linear;
}
.expanded{
height: 200px;
}
.collapsed{
height: 20px;
}
You can add a class that describes the active state ie. .active and toggle that class when switching states.
The css should look something like this:
.your-component-name{
// inactive css styling here
}
.your-component-name.active {
// active css styling here
}
Here you have a Toggle react component using the Velocity-React library, which is great for giving animations to transitions in React uis:
import React, { Component } from 'react';
import { VelocityTransitionGroup } from 'velocity-react';
export default class ToggleContainer extends Component {
constructor () {
super();
this.renderContent = this.renderContent.bind(this);
}
renderContent () {
if (this.props.show) {
return (
<div className="toggle-container-container">
{this.props.children}
</div>
);
}
return null
}
render () {
return (
<div>
<h2 className="toggle-container-title" onClick={this.props.toggle}>{this.props.title}</h2>
<VelocityTransitionGroup component="div" enter="slideDown" leave="slideUp">
{this.renderContent()}
</VelocityTransitionGroup>
</div>
);
}
};
ToggleContainer.propTypes = {
show: React.PropTypes.bool,
title: React.PropTypes.string.isRequired,
toggle: React.PropTypes.func.isRequired,
};
Hope it helps!
Related
I'm still learning React but I'm having an issue toggling a body class with a button in the menu.
const toggleSideMenu = event => {
// toggle class on click
//Below is not correct
event.getElementsByTagName('body').classList.toggle('sb-sidenav-toggled');
};`
<button onClick={toggleSideMenu} id="sidebarToggle" href="#!"><i className="fas fa-bars"></i></button>
I'm used to doing this easily in jQuery but it's not recommended to use jQuery in React because of the dom. I would appreciate any suggestions.
Thanks so much!
In this example, we are using the useState hook to keep track of the toggle state. The initial state is set to false. We are using the isToggled state in the JSX to determine what to render on the screen, and to update the text of the button.
We have an onClick event on the button, which calls the setIsToggled function and pass the negation of the current state (!isToggled), this is the way to toggle the state, every time the button is clicked.
import React, { useState } from 'react';
const MyComponent = () => {
// useState hook to keep track of the toggle state
const [isToggled, setIsToggled] = useState(false);
return (
<div>
{/* render some content or change className based on the toggle state */}
<p className={isToggled? "class1" : "classB">Toggled on</p>
<button onClick={() => setIsToggled(!isToggled)}>
{isToggled ? 'Turn off' : 'Turn on'}
</button>
</div>
);
}
export default MyComponent;
But if you need to do something more advanced, maybe you can learn more about React Context.
import React, { useState } from 'react';
// Create a context to share the toggle state
const ToggleContext = React.createContext();
const MyApp = () => {
// useState hook to keep track of the toggle state
const [isToggled, setIsToggled] = useState(false);
return (
<ToggleContext.Provider value={{ isToggled, setIsToggled }}>
<MyComponent1 />
<MyComponent2 />
{/* any other components that need access to the toggle state */}
</ToggleContext.Provider>
);
}
const MyComponent1 = () => {
// use the toggle state and toggle function from the context
const { isToggled, setIsToggled } = useContext(ToggleContext);
return (
<div>
<p className={isToggled? "class1" : "classB">Toggled on</p>
<button onClick={() => setIsToggled(!isToggled)}>
{isToggled ? 'Turn off' : 'Turn on'}
</button>
</div>
);
}
const MyComponent2 = () => {
// use the toggle state from the context
const { isToggled } = useContext(ToggleContext);
return (
<div>
{isToggled ? <p>Toggled on</p> : <p>Toggled off</p>}
</div>
);
}
export default MyApp;
A very basic example to show you how to use state to maintain whether a menu should be open or not.
It has one button that when clicked calls a function that updates the state.
It has one Menu component that accepts that state, and uses CSS to determine whether it should be "open" (ie on/off screen).
Like I said, as simple as I could make it.
const { useState } = React;
function Example() {
// The state set to either true or false
// Initially it's false / menu closed
const [ menuOpen, setMenuOpen ] = useState(false);
// When the button is clicked we take the
// previous state and toggle it - either from true
// to false, or vice versa
function handleClick() {
setMenuOpen(prev => !prev);
}
// One Menu component that accepts that state
// and one button that updates the state
return (
<div>
<Menu open={menuOpen} />
<button onClick={handleClick}>
Toggle Sidebar Menu
</button>
</div>
);
}
// Small menu (an aside element) which uses CSS
// to work out its position on the screen
// It does this by creating a classList using the default
// "menu" which it ties together with "open" but it only
// adds that if the state is true
// And then just use that joined array as the className on
// the element
// You can see in the CSS what both those classes do
function Menu({ open }) {
const menuStyle = [
'menu',
open && 'open'
].join(' ');
return (
<aside className={menuStyle}>
I am a sidebar
</aside>
);
}
ReactDOM.render(
<Example />,
document.getElementById('react')
);
.menu { width: 100px; top: 0px; left: -120px; background-color: salmon; position: fixed; height: 100vh; padding: 10px; transition-property: left; transition-duration: 0.25s;}
.open { left: 0px; }
button { position: fixed; left: 150px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
getElementsByTagName() is method of Document or Element, not react event.
What you need to do, is to look for body inside document.
Also getElementsByTagName(), returns HTMLCollection (many elements), so you need to grab first one (usually there is only one body element on page)
document.getElementsByTagName('body')[0].classList.toggle('sb-sidenav-toggled');
There is also shortcut for body element document.body, so it can be also written as:
document.body.classList.toggle('sb-sidenav-toggled');
I am trying to emulate a behavior similar to clicking on the overlay when a Modal popup is open. When clicking outside the sidenav component, I want to close all elements that are currently in a flyout mode.
I have a multi-tier nested navigation menu that is stored in its own component, Sidebar. I have the following piece of code that handles clicks that occur outside the Sidebar component:
class Sidebar extends React.Component {
...
handleClick = (e) => {
if (this.node.contains(e.target)) {
return;
}
console.log('outside');
};
componentDidMount() {
window.addEventListener('mousedown', this.handleClick, false);
}
componentWillUnmount() {
window.removeEventListener('mousedown', this.handleClick, false);
}
render() {
return (
<div
ref={node => this.node = node}
className="sidebar"
data-color={this.props.bgColor}
data-active-color={this.props.activeColor}
>
{renderSideBar()}
</div>
);
}
...
}
This part works fine - but when the flyout menus get displayed on clicking a parent menu option, I would like it to close -any- flyout menus that are currently opened.
-|
|
- Menu Item 1
|
|-option 1 (currently open)
|-option 2
- Menu Item 2
|
|-option 1 (closed)
|-option 2 (closed, clicked to expand - this is when it should close [Menu Item 1/Option 1]
The menu items are generated using <li> tags when mapping the data object containing the menu structure.
Is there a way to basically select all registered objects that have the class of 'collapse' / aria-expanded="true" and remove it? Similar to how jQuery would select dom elements and manipulate them.
I know that this is not the premise in which React works, it is just an example of the behavior I want to emulate.
As far as I understand you want to modify the DOM subtree from another component. To achive your goal you can use ref.
Using ref is helpful when you want to access HtmlElement API directly - in my example I use animate(). Please, read the documentation as it describes more of ref use cases.
Below is the simple example of animating <Sidebar/> shrinking when user clicks on <Content />.
const { useRef } = React;
function Main() {
const sidebar = useRef(null);
const handleClick = () => {
sidebar.current.hide();
};
return (
<div className="main">
<Sidebar ref={sidebar} />
<Content onClick={handleClick} />
</div>
);
}
class Sidebar extends React.Component {
constructor(props) {
super(props);
this.state = { visible: true };
this.show = this.show.bind(this);
this.sidebar = React.createRef(null);
}
show() {
if (!this.state.visible) {
this.sidebar.current.animate(
{ flex: [1, 2], "background-color": ["teal", "red"] },
300
);
this.setState({ visible: true });
}
}
hide() {
if (this.state.visible) {
this.sidebar.current.animate(
{ flex: [2, 1], "background-color": ["red", "teal"] },
300
);
this.setState({ visible: false });
}
}
render() {
return (
<div
ref={this.sidebar}
className={this.state.visible ? "sidebar--visible" : "sidebar"}
onClick={this.show}
>
Sidebar
</div>
);
}
}
function Content({ onClick }) {
return (
<div className="content" onClick={onClick}>
Content
</div>
);
}
ReactDOM.render(<Main />, document.getElementById("root"));
.main {
display: flex;
height: 100vh;
}
.sidebar {
flex: 1;
background-color: teal;
}
.sidebar--visible {
flex: 2;
background-color: red;
}
.content {
flex: 7;
background-color: beige;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I'm creating, in componentDidMount, a lots of <div>'s.
constructor (props) {
super(props)
this.state = {
componentLoaded: false,
divs: []
}
}
componentDidMount () {
this.createDivs()
}
createDivs () {
// Actually, this divs are created dinamically and with infinite scroll
let divs = <div className='container'>
<div className='item' onClick={() => { /* Add class */ }}>...</div>
<div className='item' onClick={() => { /* Add class */ }}>...</div>
<div className='item' onClick={() => { /* Add class */ }}>...</div>
/* ... n divs ... */
</div>
let newDivs = this.state.divs
newDivs.push(divs)
this.setState({
componentLoaded: true,
divs: newDivs
})
}
render () {
return {this.state.componentLoaded ? this.state.divs : null }
/* In my return, if X event occurs, re-call this.createDivs() to add more divs */
}
What I'm trying to achieve, is to toggle a class into only one of the .item divs, and then if clicking another one, remove it from the before and add it to the one was clicked.
I've tried to add an attribute to the state, but it didn't add it. I also searched for some solutions, but I always find solutions which doesn't toggle, as they are "toggled individually" in separated components.
Hoping to find some help, maybe this thing is real simple, but for now, I cannot figure out how to make it.
PS: I'm adding the createDivs into the state because it's an infinite scroll that re-uses the function, so I just push them into the state and the scroll won't go to the top again when adding the previous ones + the new ones.
In problems like these it is always helpful to determine what goes into react's state. You want the state to be as lightweight as possible (so you store only the stuff which is necessary)
class Test extends React.Component {
state = {
selectedDiv: null,
};
handleClick = id => {
this.setState(prev => ({
// sets it to null if its already active else, sets it active
selectedDiv: prev.selectedDiv === id ? null : id,
}));
};
render() {
// Array to map over
const divs = [1, 2, 3, 4];
const { selectedDiv } = this.state;
return (
<div className="container">
{divs.map(div => {
return (
<div
key={div}
className={selectedDiv === div ? "item class_to_add" : "item"}
onClick={() => this.handleClick(div)}
>Item {div}</div>
);
})}
</div>
);
}
}
In the above examples we are only storing the unique Id of the div in the state and using that to determine if the selected div is active or not, if it is then we simply remove it from the state. The above solution does not require any complex lifecycle methods, my advice would be to keep the component as simple as possible.
PS. not part of the answer but I suggest you to look into the newer hooks API its more intuitive and most probably the future of react
First, note that you're breaking a React rule here:
this.state.divs.push(divs)
You must never directly modify state. The correct thing there is either:
this.setState({divs}); // Replaces any previous ones
or
this.setState(({divs: oldDivs}) => {divs: [...oldDivs, divs]}); // Adds to any previous ones
However, the "React way" to do this would probably be not to store those divs in state at all; instead, store the information related to them in state, and render them (in render) as needed, with the appropriate classes. The information about which one of them has the class would typically either be information on the items themselves, or some identifying information about the item (such as an id of some kind) held in your component's state.
Here's an example using items that have an id:
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
// No items yet
items: null,
// No selected item yet
selectedId: null
};
}
componentDidMount() {
this.createDivs();
}
createDivs() {
// Simulate ajax or whatever
setTimeout(() => {
const items = [
{id: 42, label: "First item"},
{id: 12, label: "Second item"},
{id: 475, label: "third item"},
];
this.setState({items});
}, 800);
}
render () {
const {items, selectedId} = this.state;
if (!items) {
// Not loaded yet
return null;
}
return (
<div className='container'>
{items.map(({id, label}) => (
<div
key={id}
className={`item ${id === selectedId ? "selected" : ""}`}
onClick={() => this.setState({selectedId: id})}
>
{label}
</div>
))}
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById("root"));
.selected {
color: green;
}
.item {
cursor: pointer;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
I've made a small app that renders different components based on a Redux state. I want to apply a "fade" animation when one of the component renders. However, for some reason, it doesn't work for me. Here's what I have so far:
content.js
class Content extends Component {
render() {
const transitionOptions = {
transitionName: "fade",
transitionEnterTimeout: 500,
transitionLeaveTimeout: 500
}
if (this.props.page === 'one') {
return (
<div>
<ReactCSSTransitionGroup {...transitionOptions}>
<Comp1/>
</ReactCSSTransitionGroup>
</div>
);
} else {
return (
<div>
<ReactCSSTransitionGroup {...transitionOptions}>
<Copm2/>
</ReactCSSTransitionGroup>
</div>
);
}
}
}
style.css
.fade-enter {
opacity: 0.01;
}
.fade-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.fade-leave {
opacity: 1;
}
.fade-leave.fade-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
I've seen ReactCSSTransitionGroup being used for items being added and removed to a list, but I haven't found one example of it being used for conditional rendering. Is it achievable? Maybe there's another addon that does this?
I've seen this same problem posted many times. In short: you need to conditionally render the children inside of <ReactCSSTransitionGroup>, not <ReactCSSTransitionGroup> itself. <ReactCSSTransitionGroup> needs to mount once and then stay, it's the children that get added and removed.
content.js
class Content extends Component {
render() {
const transitionOptions = {
transitionName: "fade",
transitionEnterTimeout: 500,
transitionLeaveTimeout: 500
}
let theChild = undefined;
if (this.props.page === 'one') {
theChild = <Comp1 key="comp1" />;
} else {
theChild = <Comp2 key="comp2" />;
}
return (
<div>
<ReactCSSTransitionGroup {...transitionOptions}>
{theChild}
</ReactCSSTransitionGroup>
</div>
);
}
}
Note that you should also add a unique key prop to each child inside of a <ReactCSSTransitionGroup>. That helps the component identify which children are unique in order to properly animate them in and out.
Here is a snippet from my code
render() {
return (
<CSSTransitionGroup
transitionName="slide"
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
>
{ id === targetID ? (
<div>
<SectionList id={id} />
</div>
) : '' }
</CSSTransitionGroup>
)
}
I just learn react, and want to achieve a function :
both A,B are components, if A scroll, then B scroll
The following is my code
<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;
}
but actually I want my code like this
//what i want
<A scrollTop={this.props.scrollSeed}></A>
<B scrollTop={this.props.scrollSeed}></B>
//...
handleScroll(){
this.setState({scrollSeed: ++this.state.scrollSeed})
}
it is similar to 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
}
In other words, I want some attribute, like scrollTop(different
form <input value={}> ,because <A scrollTop={}> doesn't work) ,is bind with some state, so that I can just use setState, and they will update by themselves.
I googled before but can't find the answser. I hope that my poor English won't confuse you.
There are a number of patterns to achieve this. This sample is what I came up with to get you up and going.
First create a component class which has an oversize element for scroll effect. When dragging the scroll bar, this component calls its handleScroll React property to notify its parent component, with the value of 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 );
}
});
The parent component, aka wrapper, keeps the scroll top value in its state. Its handleScroll is passed to the child components as callback. Any scroll on the child elements triggers the callback, sets the state, results in a redraw, and updates the child component.
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 });
}
});
And render the wrapper, presuming an existing <div id="container"></div>.
ReactDOM.render(
<Wrapper />,
document.getElementById('container')
);
2019's answer
First, the fix:
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>
)
}
Second, a little explanation:
Idk what is your reason why you got here but I have used flex-direction: column-reverse for my FlatList (it's a list of elements). And I need this property for z-index purposes. However, browsers set their scroll position to the end for such elements (tables, chats, etc.) - this may be useful but I don't need that in my case.
Also, example is shown using React Hooks, but you can use older more traditional way of defining refs
this.refs is deprecated. use reactjs.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.scrollIntoView({behavior: 'smooth'});
// alternative:
// this.resultsDiv.current.scrollTop = 0;
}
render() {
return (
<div ref={this.resultsDiv} />
);
}
}
export default SomeComponent;
Here's an updated version of Season's answer, including a runnable snippet. It uses the recommended method for creating refs.
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>