Can't find a way to change reactjs element position on runtime - javascript

I wrote some react.component and i define the position as fixed.
i need to move this element position on runtime and
render(){
var t = <div className="myElement" />;
t.top = '${500}px';
t.left = '${900}px';
return t; // the element position need to be now 500, 900
}

Seems like you just need to pass some inline css rules:
render(){
const s = {top: '500px', left: '900px'};
return (
<div className="myElement" style={s} />
);
}
or, the more compact version:
render(){
return (
<div className="myElement" style={{top: '500px', left: '900px'}} />
);
}
React will automatically px if a unit is missing. So you can also do: {top: 500, left: 900}
From the docs:
The style attribute accepts a JavaScript object with camelCased properties rather than a CSS string. This is consistent with the DOM style JavaScript property, is more efficient, and prevents XSS security holes.

For this you can try the following method,
render(){
let newStyle={
top:500,
left:900,
position:"fixed",
}
return <div style={newStyle} />
}
Here you can assign any value at runtime for the location of the element during runtime by setting the value at the place of 500 and 900. Thus making the size dynamic.

Related

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.

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)

Get rendered element height before it shows up on screen (ReactJS)

I have an animated component that slides up/down depending on the prop (true or false). I'm using maxHeight: 0 to hide the component (transition is being done with CSS) and that's the default state that's being passed as prop. For the opened style I use a maxHeight much bigger than needed just to make sure the content will fit properly. After it's opened I'm able to get its height by ref and set the maxHeight accordingly.
export default class AnimatedInput extends React.Component {
constructor (props) {
super(props);
this.state = {
height: 600
}
}
componentDidUpdate(prevProps) {
var height = this.refs.inputNode ? this.refs.inputNode.clientHeight : height;
console.log(height);
if (this.props.open === false && prevProps.open === true) {
this.setState({height: height});
}
}
render () {
var {height} = this.state;
let test = this.props.open ? 'boxVisible' : 'boxHidden';
var styles = {
boxHidden: {
...
maxHeight: 0,
},
boxVisible: {
....
maxHeight: height,
}
}
return (
<div style={styles[test]} ref="inputNode">
{this.props.children}
</div>
)
}
}
There are 2 problems with this approach:
The first time it's opened and closed is not smooth due to maxHeight being larger than it should (maybe render the opened one off-screen and get its height first?)
If it's closed before fully opened the height will be lower than it should (I suppose it's an easy fix - just need to stop updating the height value).
Am I on the right track? How would you fix these? Should I stick to CSS or maybe make the transition entirely in JS. Thanks for your suggestions!
You're looking for ReactCSSTransitionGroup. I used this for the exact same thing you are.

How to position a React component relative to its parent?

I have a parent React component that contains a child React component.
<div>
<div>Child</div>
</div>
I need to apply styles to the child component to position it within its parent, but its position depends on the size of the parent.
render() {
const styles = {
position: 'absolute',
top: top(), // computed based on child and parent's height
left: left() // computed based on child and parent's width
};
return <div style={styles}>Child</div>;
}
I can't use percentage values here, because the top and left positions are functions of the child and parent's widths and heights.
What is the React way to accomplish this?
The answer to this question is to use a ref as described on Refs to Components.
The underlying problem is that the DOM node (and its parent DOM node) is needed to properly position the element, but it's not available until after the first render. From the article linked above:
Performing DOM measurements almost always requires reaching out to a "native" component and accessing its underlying DOM node using a ref. Refs are one of the only practical ways of doing this reliably.
Here is the solution:
getInitialState() {
return {
styles: {
top: 0,
left: 0
}
};
},
componentDidMount() {
this.setState({
styles: {
// Note: computeTopWith and computeLeftWith are placeholders. You
// need to provide their implementation.
top: computeTopWith(this.refs.child),
left: computeLeftWith(this.refs.child)
}
})
},
render() {
return <div ref="child" style={this.state.styles}>Child</div>;
}
This will properly position the element immediately after the first render. If you also need to reposition the element after a change to props, then make the state change in componentWillReceiveProps(nextProps).
This is how I did it
const parentRef = useRef(null)
const handleMouseOver = e => {
const parent = parentRef.current.getBoundingClientRect()
const rect = e.target.getBoundingClientRect()
const width = rect.width
const position = rect.left - parent.left
console.log(`width: ${width}, position: ${position}`)
}
<div ref={parentRef}>
{[...Array(4)].map((_, i) => <a key={i} onMouseOver={handleMouseOver}>{`Item #${i + 1}`}</a>)}
</div>
The right way to do this is to use CSS. If you apply position:relative to the parent element then the child element can be moved using top and left in relation to that parent. You can even use percentages, like top:50%, which utilizes the height of the parent element.

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

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));

Categories