I'm stuck at rendering a component insider a div. My code is like below, I want to render the div with classname RequestNewOrgBtn inside the parentDiv. How can I do it at runtime of render?
const labelItem = Array.from(document.querySelectorAll('label'))
.find(el => el.textContent === 'External Org Name');
const parentDiv = labelItem?.parentNode?.parentNode?.parentNode;
return(
<>
{
//render below div inside parentDiv
<div className="RequestNewOrgBtn">
<Button disabled={false} onClick={onAddClick}>
{ "Request New External org" }
</Button>
<RequestExternalOrgModal
isOpen={ShowReqExOrgModal}
onClose={onReqExOrgModalClose} />
</div>
}
</>
);
Probably the easiest way to do this would be to render the appropriate parts of your React app into the element in question, similar to how you would render <App /> into your root element.
For example...
import { createRoot } from "react-dom/client";
import RequestNewOrgBtn from "./RequestNewOrgBtn"; // your component
const labelItem = Array.from(document.querySelectorAll("label")).find(
(el) => el.textContent === "External Org Name"
);
const parentDiv = labelItem?.parentNode?.parentNode?.parentNode;
if (parentDiv) {
// create a new root for your button component
const btnRootElement = document.createElement("div");
// append it into the found `parentDiv`
parentDiv.appendChild(btnRootElement);
const btnRoot = createRoot(btnRootElement);
btnRoot.render(<RequestNewOrgBtn />);
}
For React 16, you just use the ReactDOM equivalent
import ReactDOM from "react-dom";
// ...
ReactDOM.render(<RequestNewOrgBtn />, btnRootElement);
This is a little ambiguous. But, if I am understanding correctly, I think you can set the innerHTML to append the div
parentDiv.innerHTML += "<div>Your div content here</div>"
better yet, set your div as a variable and then just += the variable for cleaner code.
const myDiv = "<div>Your div content here</div>"
parentDiv.innerHTML += myDiv
Used this to make sure I was remembering correctly
Related
I have a code that is only rendered after some data is fetched from server and variables are set. When using svg.js, it uses SVG.AddTo("#someID"), but the div containing the ID has not been rendered yet because of the conditional rendering. How do I delay the SVG.AddTo, to after the div has been rendered and the id exist? Here is the code (Some things have been removed, for example server fetching):
import React, { useEffect, useState, useRef } from "react";
import {
CCol,
CRow,
} from "#coreui/react";
import * as SVG from '#svgdotjs/svg.js'
const website = () => {
var draw = SVG().addTo('#svgHere').size('100%', '100%')
var rect = draw.rect(100, 100).attr({ fill: '#f06' })
return (
(typeof dataFromServer !== "undefined") &&
<CCol>
<CRow>
<div id="svgHere">
</div>
</CRow>
</CCol>
);
};
export default website;
I also tried, as by the documentation of svg.js adding this:
SVG.on(document, 'DOMContentLoaded', function () {
var draw = SVG().addTo('#test').size('100%', '100%')
var rect = draw.rect(100, 100).attr({ fill: '#f06' })
})
But then the SVG is never rendered. I later want to create a new svg every time the value of a state changes. How can I remove the current draw? I know about useEffects dependencies but I do not know how I can remove the current SVG and replace it with another one?
Thank you for your help!
Make an component and put your logic there and then in Website component return
return (
(typeof dataFromServer !== "undefined") &&
<CCol>
<CRow>
<Svg/>
</CRow>
</CCol>
);
Later when you want a different svg based on your state changes pass whatever you need as props to
React Component
import React, {useState} from 'react';
import './CounterButton.css';
const CounterButton = (props)=>{
const [currentCount, setCurrentCount] = useState(0);
const handleClick = (event)=>{
if(currentCount == 9){
event.target.classList.toggle('bound-hit');
}
setCurrentCount(currentCount+props.incrementVal);
};
return (
<div class="count-container">
<button onClick={handleClick}>+{props.incrementVal}</button>
<p>{currentCount}</p>
</div>
);
};
export default CounterButton;
External stylesheet for this component
.count-container {
display: flex;
padding: 10px;
}
.count-container > button {
width: 50px;
margin: 0 10px;
}
.bound-hit {
color: red;
}
I have a react component and stylesheet for that component. In this case it toggle class bound-hit to the classList of button. I could select button using event.target and but I want to toggle this class to the <p></p> tag inside my div. My question is how can I select that p tag using event. p tag is like a sibling of button. div with class count-container is parent. I can also select parent div by event.target.parent but I want to select p tag and toggle class bound-hit to that.. How can I do that?
I don't think you need a React specific answer here.
In vanilla JS you can use the nextElementSibling method.
const handleClick = (event) => {
const p = event.target.nextElementSibling
}
Or instead you can do it in CSS with the adjacent sibling combinator.
.bound-hit + p {
// apply styles to the <p> that's just after .bound-hit in the DOM
}
However, if you "manually" add a class in a react component (meaning that this class gets added to the DOM without any representation in the state), some virtual DOM reconciliations might end up removing it.
In a lot of cases, this won't be a problem, but if it is, then you should use a state for it. Here's a simplified example of what that would look like:
const [pClass, setPClass] = useState('')
const handleClick = () => {
setPClass('bound-hit')
}
return (
<p className={pClass} />
)
The question shouldn't be "how to select a sibling" but "how to assign CSS class to the P element on [condition]".
If a React component directly has ownership over the (child) elements you can simple change the components state and apply it to the class list of the element using className.
Doing any DOM manipulation/traversing within a component is mainly bad form using React and overcomplicates the solution.
const CounterButton = (props)=>{
const [currentCount, setCurrentCount] = useState(0);
const [currentClass, setCurrentClass] = useState();
const handleClick = (event)=>{
if(currentCount == 9){
setCurrentClass('bound-hit');
}
setCurrentCount(currentCount+props.incrementVal);
};
return (
<div class="count-container">
<button onClick={handleClick}>+{props.incrementVal}</button>
<p className={currentClass}>{currentCount}</p>
</div>
);
};
In normal JavaScript you can grab an element by its id and add a style to it.
For example:
var element = document.getElementById("myElement");
element.style.backgroundColor = "#f5f5f5";
My question is how you can do this in react. Is it even possible to add this style?
In react im using onChange in a function outside the render(). I looked at the React DOM for styling and tried but since styling is in different function it will tell me how the variable is undefined.
this is my code:
ChangeImage() {
var imgStyles = {
backgroundColor: '#000',
padding: 5,
}
}
render() {
return (
<div className="class">
<div className="img-surround">
<img
src={this.state.file}
id="img"
style={imgStyles}/>
</div>
Everything is working except styles and I even tried putting in different functions
If you want to render the element with the style you can return the element like this in a react functional component:
return <div style={{backgroundColor: "#f5f5f5"}}></div>
If you want the element to only have that style in a certain condition you can use the useState hook in a react functional component:
const [myState, setMyState] = useState(false);
return <div style={myState && {backgroundColor: "f5f5f5"}}></div>
And you should change myState's value using setMyState however you like. For example:
const [myState, setMyState] = useState(false);
return <div onClick={() => myState ? setMyState(true) : setMyState(false)} style={myState && {backgroundColor: "f5f5f5"}}></div>
In this example whenever you click on the div the style is added or removed by case
I want my code to toggle a person handler, Before it was working but since I split into components, It seem to have broken.
Toggle happens on button click (see inside return statement <
button className={btnClass}
onClick={props.toggler}>Button</button>
Here is my entire cockpit.js file (inside src/components/cockpit/cockpit.js).
import React from 'react';
import classes from './cockpit.css';
const Ccockpit = (props) => {
const assignedClasses = [];
let btnClass = ''
if (props.cocPersonState) {
btnClass = classes.red;
console.log(".......")
}
if (props.cocperson <= 2) {
assignedClasses.push(classes.red)
}
if (props.cocperson <= 1) {
assignedClasses.push(classes.bold)
}
return(
<div className={classes.cockpit}>
<h1> Hi I am react App</h1>
<p className={assignedClasses.join(' ')}>hey </p>
<button className={btnClass}
onClick={props.toggler}>Button</button>
</div>
);
}
export default Ccockpit;
and inside App.js
return (
<div className={classes.App}>
<Ccockpit>
cocPersonState = {this.state.showPerson}
cocperson = {this.state.person.length}
toggler = {this.togglerPersonHandler}
</Ccockpit>
{person}
</div>
)
}
}
and this is my togglerpersonHandler code.
togglerPersonHandler = () => {
const doesShow = this.state.showPerson;
this.setState({
showPerson: !doesShow
});
}
I can't see to figure out that why it won't toggle and console.log/change color to red (It isn't changing the state). Can someone please review and figure out the mistake?
Your JSX still isn't right. Please review the JSX syntax with regards to giving it props/children.
You have this:
<Ccockpit>
cocPersonState = {this.state.showPerson}
cocperson = {this.state.person.length}
toggler = {this.togglerPersonHandler}
</Ccockpit>
But those values aren't children, they're properties. So they need to be in the opening tag, like this:
<Ccockpit
cocPersonState = {this.state.showPerson}
cocperson = {this.state.person.length}
toggler = {this.togglerPersonHandler}/>
Revisit some React tutorials to see how JSX should be structured and how it works.
Is it possible to get the element object from JSX before it's mounted?
In the following code for example:
import React from 'react';
import ReactDOM from 'react-dom';
...
const container = <div id='something'>My simple div</div>;
const element = container.??? // Get Node/Element/HTMLElement from 'container'.
I know there is a ref attribute but this method doesn't seem to work. Also, I find it a bit cumbersome compared to something that's inline.
let element = null;
const container = <div id='something' ref={(containerElement) => {element = containerElement;}} />;
This probably doesn't work because the component isn't mounted yet (which is the use-case I'm looking for).
The real DOM element appears when the virtual React element is rendered, so you need to render container first and then use either ref:
const container = <div ref={_element => element = _element}>My simple div</div>;
let element;
ReactDOM.render(container, document.body);
alert(element);
<script src="//cdn.jsdelivr.net/npm/react#16.2.0/umd/react.production.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/react-dom#16.2.0/umd/react-dom.production.min.js"></script>
Or a DOM query:
const container = <div id="something">My simple div</div>;
ReactDOM.render(container, document.body);
const element = document.querySelector('#something');
alert(element);
<script src="//cdn.jsdelivr.net/npm/react#16.2.0/umd/react.production.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/react-dom#16.2.0/umd/react-dom.production.min.js"></script>