How to Detect Overflow of React Component Without Reactdom

How to detect overflow of React component without ReactDOM?

In addition to @jered's excellent answer, i'd like to mention the qualifier that a ref will only return an element that directly has access to the various properties of regular DOM elements if the ref is placed directly on a DOM element. That is to say, it does not behave in this way with Components.

So if you are like me and have the following:

var MyComponent = React.createClass({
render: function(){
return <SomeComponent id="my-component" ref={(el) => {this.element = el}}/>
}
})

and when you attempt to access DOM properties of this.element (probably in componentDidMount or componentDidUpdate) and you are not seeing said properties, the following may be an alternative that works for you

var MyComponent = React.createClass({
render: function(){
return <div ref={(el) => {this.element = el}}>
<SomeComponent id="my-component"/>
</div>
}
})

Now you can do something like the following:

componentDidUpdate() {
const element = this.element;
// Things involving accessing DOM properties on element
// In the case of what this question actually asks:
const hasOverflowingChildren = element.offsetHeight < element.scrollHeight ||
element.offsetWidth < element.scrollWidth;
},

How to check if a div is overflowing in react functional component

As Jamie Dixon suggested in the comment, I used useLayoutEffect hook to set showLink true. Here is the code

Component

import React from "react";
import "./styles.css";

export default function App(props) {
const ref = React.createRef();
const [showMore, setShowMore] = React.useState(false);
const [showLink, setShowLink] = React.useState(false);

React.useLayoutEffect(() => {
if (ref.current.clientWidth < ref.current.scrollWidth) {
setShowLink(true);
}
}, [ref]);

const onClickMore = () => {
setShowMore(!showMore);
};

return (
<div>
<div ref={ref} className={showMore ? "" : "container"}>
{props.text}
</div>
{showLink && (
<span className="link more" onClick={onClickMore}>
{showMore ? "show less" : "show more"}
</span>
)}
</div>
);
}

CSS

.container {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 200px;
}

.link {
text-decoration: underline;
cursor: pointer;
color: #0d6aa8;
}

Detect click outside React component

The following solution uses ES6 and follows best practices for binding as well as setting the ref through a method.

To see it in action:

  • Hooks Implementation
  • Class Implementation After React 16.3
  • Class Implementation Before React 16.3

Hooks Implementation:

import React, { useRef, useEffect } from "react";

/**
* Hook that alerts clicks outside of the passed ref
*/
function useOutsideAlerter(ref) {
useEffect(() => {
/**
* Alert if clicked on outside of element
*/
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
alert("You clicked outside of me!");
}
}
// Bind the event listener
document.addEventListener("mousedown", handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
}

/**
* Component that alerts if you click outside of it
*/
export default function OutsideAlerter(props) {
const wrapperRef = useRef(null);
useOutsideAlerter(wrapperRef);

return <div ref={wrapperRef}>{props.children}</div>;
}

Class Implementation:

After 16.3

import React, { Component } from "react";

/**
* Component that alerts if you click outside of it
*/
export default class OutsideAlerter extends Component {
constructor(props) {
super(props);

this.wrapperRef = React.createRef();
this.handleClickOutside = this.handleClickOutside.bind(this);
}

componentDidMount() {
document.addEventListener("mousedown", this.handleClickOutside);
}

componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClickOutside);
}

/**
* Alert if clicked on outside of element
*/
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.current.contains(event.target)) {
alert("You clicked outside of me!");
}
}

render() {
return <div ref={this.wrapperRef}>{this.props.children}</div>;
}
}

Before 16.3

import React, { Component } from "react";

/**
* Component that alerts if you click outside of it
*/
export default class OutsideAlerter extends Component {
constructor(props) {
super(props);

this.setWrapperRef = this.setWrapperRef.bind(this);
this.handleClickOutside = this.handleClickOutside.bind(this);
}

componentDidMount() {
document.addEventListener("mousedown", this.handleClickOutside);
}

componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClickOutside);
}

/**
* Set the wrapper ref
*/
setWrapperRef(node) {
this.wrapperRef = node;
}

/**
* Alert if clicked on outside of element
*/
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
alert("You clicked outside of me!");
}
}

render() {
return <div ref={this.setWrapperRef}>{this.props.children}</div>;
}
}

Accessing child refs without passing it from parent

Found an answer here Getting DOM node from React child element

The answer is slightly old so I rewrote a bit of it with callback refs instead of using findDOMNode (https://github.com/yannickcr/eslint-plugin-react/issues/678).

ParentComponent extends React.Component {
constructor() {
this.myRef = React.createRef();
}

render() {
return (
<ChildComponent>
<div ref={myRef}>Blah</div>
<ChildComponent>
);
}
}

ChildComponent extends React.Component {

constructor() {
this.myElement = null;
this.myRef = element => {
this.myElement = element;
};
}

render() {
const {children} = this.props.children;
return (
<div>
{React.cloneElement(children, { ref: this.myRef})};
</div>
)
}
}

Note: the above only works with child component only having child from parent

How to detect a React component vs. a React element?

ReactComponent.prototype.isReactComponent = {};

33 of /node_modules/react/lib/ReactComponent.js

Install using npm. At this point, there is no direct method available to check for its validity. What you are doing is correct.



Related Topics



Leave a reply



Submit