Reactjs: How to get a css-class attribute from a mounted <div>? - javascript

Lets say I have a react DOM element like this one:
render () {
...
return (
<div className = "widePaddingRight" style = {{width: "100px"}}
ref = "pickMe"
>
...
</div>
)
}
CSS:
.widePaddingRight{
paddingRight: 20px
}
If I access this element later and try to get its width like that:
componentDidMount () {
var elem = this.refs.pickMe.getDOMNode().getBoundingClientRect()
console.log(elem.width)
}
I get 120 in my console. My expected result was 100. Since I have to calculate with the original width I have to get the padding-attributes of the element.
Question: How can I get the paddingRight attribute of my component in my react-class?
Update
With the input of #Mike 'Pomax' Kamermans I was able to solve the underlying problem (thank you for that): Just add box-sizing: border-box to the CSS. Now getBoundingClientRect() gives 100 instead of 120.
I still dont know how to get a css class-attribute from a mounted div - any suggestions?

You need window.getComputedStyle.
const style = window.getComputedStyle(React.findDOMNode(this.refs.pickMe));

Related

Can react simply change CSS style by selector that's defined elsewhere

To start, I am working with react-swipe-to-delete-component, but I feel that should make little difference in the question.
I am trying to change the background-color property of a "built out" element. I have no control over the class name as the plugin uses it, and I cannot assign it (I think) a separate class name as it stands. Is there a way to change the style of a element solely based on selector, like in vanilla JavaScript?
I have this element <SwipeToDelete>. It builds out a div that I need to access by the selector:
<div class="swipe-to-delete">
<div class="js-delete">
And thus I need to be able to access
.swipe-to-delete .js-delete
as a selector.
Is there a way like in JS IE document.getElementsByClassName('.swipe-to-delete .js-delete')[0].style.background-color = "#FFF")
I need to change the background color based on which function is called:
const [isRight, setRight] = useState(false);
const [isLeft, setLeft] = useState(false);
const onLeft = (...args) => {
// Make Mask Red with Icon
console.log('Set left to true');
setLeft(true);
}
const onRight = (...args) => {
// Make Mask Green with icon
console.log('Set right to true');
setRight(true);
}
<SwipeToDelete
onLeft={onLeft}
onRight={onRight}
>
This works.. I just don't know how to incorporate this pseudo statement
isRight ? '.swipe-to-delete .js-delete'.backgroundColor="green" : ''
Since I can't access <SwipeToDelete>'s inner workings to set a class name somewhere, without modifying the node-module code. I really am stuck here.
I just want to simply change the background color of .swipe-to-delete .js-delete depending on right or left function. Am I looking at this the wrong way?
There is a classNameTag prop you can use to define a className on the wrapper element for <SwipeToDelete> (the element with className="swipe-to-delete").
Based on the swipe direction you set the className accordingly:
<SwipeToDelete
classNameTag={isRight ? "is-right" : isLeft ? "is-left" : ""}
onLeft={onLeft}
onRight={onRight}
>
And styling with CSS:
.swipe-to-delete.is-right .js-delete {
background-color: green;
}
.swipe-to-delete.is-left .js-delete {
background-color: red;
}

React - syntax for passing computed styles to a div

I'm very new to the language of react. I seem to continuously get an unexpected token error on the ":". What exactly is the syntax for putting multiple styles inside the Box component shown below? Alongside that, how does one go about putting multiple of these Box components, each one having its margin changed and put inside of an array, displayed on a website.
ncaught SyntaxError: /Inline Babel script: Unexpected token, expected "}" (51:73)
const Box = (props) => <div style={"margin-left" : props.spacing, "width" : props.width, "height" : props.height, "background-color" : props.color}></div>
|
^
The box component takes multiple sub-components such as margin-left (I'm not even sure if I can use this within React) and so on. I then have a for loop that continuously adds box components to an array each with a different margin so that it ends up really displaying a row of different elements inside the div.
class StoryPage extends React.Component {
render(){
const Box = (props) => <div style={"margin-left" : props.spacing; "width" : props.width; "height" : props.height; "background-color" : props.color;}></div>
const val = 0
const boxArray = []
for(let i = 0; i < 10; i++){
val += 100
boxArray.push(<Box spacing = {val} width = "100px" height = "100px" color = "black" />)
}
return(
<div>
{boxArray}
</div>
)
}
}
What I essentially expect to happen is have the array of box elements be displayed. However, I'm not really sure how I'm supposed to go about doing this.
Your “passing an object literal as a prop”-syntax is wrong — explanation below.
React props are passed as follows:
string literal
<Component strProp='hello' />
// or
<Component strProp={'hello'} />
variable
<Component strProp={this.props.foo} />
array literal
<Component arrProp={[1, 2, 3]} />
object literal
<Component objProp={{foo: 'bar'}} />
See the double curly-brackets? One pair is needed to enclose any non-string-literal expression passed as prop, and the other is simply part of the object literal notation.
In contrast, this:
<Component objProp={foo: 'bar'} /> // <- WRONG
would not work because foo: 'bar' is not an expression.
Hugo is right. Also you don't want to add larger margin lefts to each element, margin-left specifies distance from border to element on the left. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Model/Introduction_to_the_CSS_box_model
You can set the property display to "inline" on all your divs to change the layout of divs from block to inline. Or just not do anything and they'll still all display.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flow_Layout
Your problem is this line:
const Box = (props) => <div style={"margin-left" : props.spacing; "width" : props.width; "height" : props.height; "background-color" : props.color;}></div>
You have provide wrong style attribute, you need to provide like this:
const Box = (props) => (
<div
style={{
marginLeft: props.spacing,
width: props.width,
height: props.height,
backgroundColor: props.color
}}
/>
);
Notice that style attribute should contain double curly braces and should separate properties with a comma ,
Demo
Note: In React, inline style name should be in camelCase.
For Example,
margin-left should be marginLeft.
background-color should be backgroundColor.

Why can't I remove the background-attachment property?

So I'm trying to remove the background attachment property with a media query at a max-width of 1024px. I'm doing this just by going background-attachment: none except my devtools is flashing an error and has that property crossed out? Any ideas?
https://jsfiddle.net/dfwg2nbv/1/
const ham = document.querySelector('.ham-menu');
const nav = document.querySelector('nav');
const header = document.querySelector('header');
const promise = document.querySelector('.promise');
const services = document.querySelector('.services');
const testimony = document.querySelector('.testimony');
header.style.removeProperty('background-attachment');
//detect mobile
// if ("ontouchstart" in document.documentElement) {
// removeProps(header);
// removeProps(promise);
// removeProps(services);
// removeProps(testimony);
// }
ham.addEventListener('click', animateMenu);
function animateMenu() {
nav.classList.toggle('hamburger-open');
}
// function removeProps(node) {
// node.style.removeProperty('background-attachment');
// node.style.removeProperty('background-size');
// }
You can remove the background using jquery:
$("header").css("background-image", "none");
Example:
https://codepen.io/seyyedmojtaba72/pen/gJqLGE
You're attempting to modify the style object (which only reflects the styles set via the style attribute, not via stylesheets), so it's not set there for it to be removed. You can override it by setting it back to the default value of scroll.
header.style.backgroundAttachment='scroll';
none isn't a valid value for the background-attachment property.
Also, that's not how you'd use removeProperty. It's not a method of style.
What you could do though is either set it to a blank value of you're trying to remove the property from an inline style, like:
header.style.backgroundAttachment = '';
Or you could set it to the initial value, if you've set it something else in a stylesheet, like:
header.style.backgroundAttachment = 'initial';
Or just set it to another specific value, similar to above.

How do I style a div inside a component without passing props to that component (I'm using a package)

I'm using the react-scrollbar package to render a scrollbar for my my content. What I also want is a arrow button that, on click, moves to a certain scrollbar area. The problem is, I'm trying to style (marginTop) a class inside my component.
This is my attempt:
// MY COMPONENT
scrollToNextUpload = () => {
const NextUpload = 400
this.setState({ marginTop : this.state.marginTop + NextUpload }, () => document.getElementsByClassName('scrollarea-content')[0].style.marginTop = "'" + this.state.marginTop + "px'")
}
// MY RENDER
render () {
<ScrollArea>
// my content
<div onClick={this.scrollToNext}></div>
</ScrollArea>
}
What is actually rendered
<div class='scrollarea'>
<div class='scrollarea-content'>
// my content
<div onClick={this.scrollToNext}></div>
</div>
</div>
What I want
To make my area with the scrollbar scroll, I have to add a marginTop style to the 'scrollarea-content'. I could do this by passing props to the < ScrollArea > and then use them inside the installed package; but I'm trying to avoid altering the original package content.Also, is there another way how I could scroll by click and is there someone else who's experienced with that NPM Package?
Most libraries give props to apply style to child components, in this library you can pass a className to the contentClassName or use inline style in contentStyle prop :
<ScrollArea contentStyle={{ marginTop: 10 }}>
An another way is to write css to add style to the scrollarea-content class.
In a .css file :
.scrollarea-content {
margin-top: 10px;
}
Edit: In your case you can programatically change the marginTop style by using the props like this :
scrollToNextUpload = () => {
const NextUpload = 400;
this.setState(prevState => ({ marginTop : prevState.marginTop + NextUpload }));
}
render () {
<ScrollArea contentStyle={{ marginTop: this.state.marginTop }}>
// my content
<div onClick={this.scrollToNext}></div>
</ScrollArea>
}
Note the use of a functional setState to prevent inconsistencies when next state value depends on the previous state.

What does the .current property of the querySelector method refer to?

I came across this line of code via a snippet on https://usehooks.com,
document.querySelector('body').current
I haven't been able to find .current in the specification at all.
I was hoping someone could clarify its purpose in this context.
It's being used within the IntersectionObserver API in the full example (below) - perhaps the API is exposing the property?
Any help is much appreciated. Thanks in advance.
Following is the full source code:
import { useState, useEffect, useRef } from 'react';
// Usage
function App() {
// Ref for the element that we want to detect whether on screen
const ref = useRef();
// Call the hook passing in ref and root margin
// In this case it would only be considered onScreen if more ...
// ... than 300px of element is visible.
const onScreen = useOnScreen(ref, '-300px');
return (
<div>
<div style={{ height: '100vh' }}>
<h1>Scroll down to next section 👇</h1>
</div>
<div
ref={ref}
style={{
height: '100vh',
backgroundColor: onScreen ? '#23cebd' : '#efefef'
}}
>
{onScreen ? (
<div>
<h1>Hey I'm on the screen</h1>
<img src="https://i.giphy.com/media/ASd0Ukj0y3qMM/giphy.gif" />
</div>
) : (
<h1>Scroll down 300px from the top of this section 👇</h1>
)}
</div>
</div>
);
}
// Hook
function useOnScreen(ref, margin = '0px') {
// State and setter for storing whether element is visible
const [isIntersecting, setIntersecting] = useState(false);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
// Update our state when observer callback fires
setIntersecting(entry.isIntersecting);
},
{
rootMargin: margin,
root: document.querySelector('body').current
}
);
if (ref.current) {
observer.observe(ref.current);
}
return () => {
observer.unobserve(ref.current);
};
}, []); // Empty array ensures that effect is only run on mount and unmount
return isIntersecting;
}
document.querySelector('body').current is just a property of the body element, which has nothing to do with document.querySelector. It may have been set somewhere else as it is not an existing property of the body element.
var body = document.querySelector("body");
console.log("body.current:", "body.current");
body.current = "SOMEVALUE";
console.log("After setting body.current");
console.log("body.current:", "body.current");
Sorry to disappoint, but it doesn't do anything. It's just a way to supply undefined to the IntersectionObserver API. If you replace document.querySelector('body').current with undefined or remove the entire root field altogether, you still get the same result.
I removed that field to test it to verify the same behavior. Try it yourself in the Codesandbox link here.
As seen by this comment on the example, it can be removed entirely:
You can remove root entirely, since it defaults to the viewport anyway (also document.querySelector('body').current is always undefined, could be document.body but isn't needed anyway)

Categories