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
Navigationduplicated Navigating to Current Location ("/Search") Is Not Allowed
Get High-Order Block'S Id on Click
Bootstrap Modal Only Showing Backdrop
Focus Next Input Once Reaching Maxlength Value
Does Jest Swallow Console.Log Statements How to Change This
How to Make a Modal Popup to Take an Input Value Using Jquery or JavaScript
How to Create a Horizontal Scrolling Chart.Js Line Chart With a Locked Y Axis
Jquery Change Event Called Two Times
Starting the Week on Monday With Isoweekday()
Blob Createobjecturl Download Not Working in Firefox (But Works When Debugging)
Node.Js Document Is Not Defined
What Does an Exclamation Mark Before a Variable Mean in JavaScript
How to Parse Through Local Json File in React Js
How to Load a Font File in Vuejs and Webpack
Check If a Key Exists Inside a Json Object
How to Toggle Class to a Div Element in Reactjs