How to get children div via parent useRef in Reactjs - reactjs

I have div like that
const indexRef = useRef();
<div className='indexBx' ref={indexRef}>
<span className='active'>01</span>
<span className='active'>02</span>
<span className='active'>03</span>
</div>
So now I want to change the secondary span classname via indexRef like something
indexRef.current.span:nth(2).className = ???
How can I do that

// change class of second child
indexRef.current.children[1].className = 'passive'

As indexRef.current with contain the reference to the div.indexBx element. You can call on that any function which allows to retrieve any DOM element from a given parent element like this
indexRef.current.querySelector('span:nth(2)');
This will return the second span
Here is how you can query sub element after you have already access to their parent element using HTML and Javascript. This will work exactly the same in react when you get access to the indexRef.current parent element
let indexRef = document.querySelector('.indexBx');
let span = indexRef.querySelector('span:nth-child(2)');
console.log(span.innerText);
<div class='indexBx'>
<span class='active'>01</span>
<span class='active'>02</span>
<span class='active'>03</span>
</div>
After you have access to the span, you can call normal javascript to append another class to that span
let span = indexRef.current.querySelector('span:nth-child(2)');
span.classList.remove('old_class_name');
span.classList.add('new_class_name');

You can use querySelector and getElementsByClassName on the HTMLDivElement contained in the ref.
Here is an exemple : https://codesandbox.io/s/naughty-ellis-pywpyr
import "./styles.css";
import { useRef } from "react";
export default function App() {
const indexRef = useRef();
const changeClassName = () => {
const span = indexRef.current.querySelector("span:nth-child(2)");
span.setAttribute("class", "changed");
console.log(indexRef, span);
};
return (
<div className="indexBx" ref={indexRef}>
<span className="active">01</span>
<span className="active">02</span>
<span className="active">03</span>
<button onClick={() => changeClassName()}>Change class</button>
</div>
);
}
But this approach is not the best to change a className you should just put javascript logic in the className of the span like this instead of creating a ref for that and manipulating the HTML element:
<span className={`${isChanged} ? 'changed' : 'active'`}>02</span>

As you have mentioned that you need to update the class of the span using ref from a different function, I have simulated a sample app with Parent and Child components. And updating the class of the 2nd span on click of the button Click Me
const { useRef } = React;
const ChildComponent = ({ indexRef, onChange }) => {
return (
<div className="indexBx" ref={indexRef}>
<span className="active">01</span>
<span className="active">02</span>
<span className="active">03</span>
</div>
);
};
const ParentComponent = () => {
const indexRef = useRef(null);
const onClick = () => {
if (indexRef.current) {
const div = indexRef.current;
console.log(div.children[2].className);
div.children[2].classList.add("test");
console.log(div.children[2].className);
}
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<ChildComponent indexRef={indexRef} />
<button onClick={onClick}>Click Me</button>
</div>
);
};
ReactDOM.render(<ParentComponent />, document.getElementById("react"));
.test {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Related

How can we create a editable `<code>` tag on fly and add different attributes to that

On click on Code button, how can we create a editable <code> tag on fly and add different attributes in react web app ?
Or may be an editable field display as code tag ? Could someone please advise here ?
import React, { useState } from 'react';
import { useNavigate } from "react-router-dom";
const Admin = () => {
const [createCode, setCreateCode] = useState("");
const navigate = useNavigate();
const createCodeSection = () => {
const newElement = React.createElement('code', {key: 'ele'+ new Date().getTime(), className:'codehighlight'}, `--sample code to enter-- `,);
setCreateCode(createCode => [...createCode, newElement]);
}
const handleLogout = () => {
localStorage.removeItem('loginEmail');
navigate("/login");
};
return (
<div id="App">
<div className='adminSection'>
<div className='row'>
<div className="logout">
<img src="/images/logout.png" alt="Logout" onClick={handleLogout}></img>
</div>
<div className='createBlogSection'>
<div className='row'>
<button onClick={createCodeSection}>Code</button>
<button>Image</button>
<button>Code</button>
</div> <br></br>
<textarea>
{createCode}
</textarea>
</div>
</div>
</div>
</div>
)
}
export default Admin;
css:
.codehighlight{
background-color: #353232;
color: #fff;
}

React change css style of a div in another component by button clicking in another component

on my Project I have a banner on top of my site with 2 buttons. when I click the button profile I want it to change the css style of a div in another component.
this is my code for the banner:
import Profile from "./Profile";
function Banner() {
const invis=false;
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={Profile.changeStyle}>Profile</button>
</span>
</div>
);
}
export default Banner;
this is my code for the div in the other component:
import "../index.css";
import React, { useState } from "react";
const Profile = () => {
const [style, setStyle] = useState("profile-hidden");
const changeStyle = () => {
console.log("you just clicked");
setStyle("profile-displayed");
};
return (
<div>
<div className={style}> hellllo</div>
</div>
);
};
export default Profile;
I can only find information about this with parent-child components.
They said I should use a usestate import but I can't seem to get it working. what's the proper way to do this?
All you need is lift your state to parent component, if you have a long trip to your common ancestor you can try to use a context. Attached a working example. Hope it helps!
const Banner = ({ onClickHandler }) => {
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={() => onClickHandler()}>Profile</button>
</span>
</div>
)}
const Profile = ({ style }) => {
return (
<div>
<div className={style}>I'm your profile :)</div>
</div>
);
};
const App = () => {
// We lift the state
const [style, setStyle] = React.useState("profile-hidden");
const profileHandler = () => {
setStyle(style === 'profile-hidden'
? 'profile-displayed'
: 'profile-hidden')
}
return(
<div>
<Banner onClickHandler={profileHandler} />
<Profile style={style} />
</div>
)
}
// Render
ReactDOM.createRoot(
document.getElementById("root")
).render(
<App />
);
.profile-hidden {
display: none;
}
.profile-displayed {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
<div id="root"></div>
You cannot use this syntax for React Components COMPONENT.method
, in your case onClick={Profile.changeStyle} !
Instead you should make Banner parent component and use Profile component as child inside it or vise versa !
then You should pass the state style as props so then you will be able to use its value.
your code should look like this :
function Banner() {
const [style, setStyle] = useState("profile-hidden");
const changeStyle = () => {
console.log("you just clicked");
setStyle("profile-displayed");
};
return (
<div className="banner">
<span className="bannerbtnsettings">
<button className="btnbannersettings">Settings</button>
</span>
<span className="bannerbtnprofile">
<button className="btnbannerprofile" onClick={changeStyle}>Profile</button>
</span>
<Profile style={style} />
</div>
);
}
export default Banner;
and your Profile component :
const Profile = (props) => {
return (
<div>
<div className={props.style}> hellllo</div>
</div>
)
}

adding and removing a classList in react js

I am using functional component in react js , in the below code
the class right-panel-active is not being added / is undefined. Someone help to enable the class be added when the button is toggled
import React from 'react';
import './style.css';
import {
Modal,
DropdownMenu
} from '../MaterialUI';
/**
* #author
* #function Header
**/
const Header = (props) => {
const container = () => {
document.getElementById('container');
}
const signUpButton = () => {
container.classList.add('right-panel-active');
};
const signInButton = () => {
container.classList.remove('right-panel-active');
};
return (
<div className="header">
<div className="container" id="container">
<button className="ghost" id="signIn" onClick={signInButton} >Sign In</button>
</div>
<div className="overlay-panel overlay-right">
<p>Enter your personal details and start journey with us</p>
<button className="ghost" id="signUp" onClick={signUpButton} >Sign Up</button>
</div>
</div>
)
}
export default Header
You are not utilising any of React's functionality.
Read about state management in React
and Event Handlers in React
const Header = (props) => {
const [isContainerActive, setIsContainerActive] = React.useState(false);
const signUpButton = () => {
setIsContainerActive(false);
};
const signInButton = () => {
setIsContainerActive(true);
};
return (
<div className="header">
<div id="container" className={`container${isContainerActive ? " right-panel-active" : ""}`}>
<button className="ghost" id="signIn" onClick={signInButton}>Sign In</button>
</div>
<div className="overlay-panel overlay-right">
<p>Enter your personal details and start journey with us</p>
<button className="ghost" id="signUp" onClick={signUpButton}>Sign Up</button>
</div>
</div>
);
}
ReactDOM.render(<Header />, document.getElementById("root"));
.header {height: 120px;}
.container {float:left;}
.overlay-right {display: none;background: red;float:right;height:100%;}
.right-panel-active ~ .overlay-right {display: inline-block;}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
PS: I also recommend https://www.npmjs.com/package/classnames , or the cx library for className management.
I think the best solution for this is to making a state and handle the style by a ternarian
function Welcome(props) {
const {name} = props;
return (
<h1 style={name === 'Sara' ? right-panel-active : right-panel-inactive}>Hello, {name}</h1>
)}
function App() {
return (
<div>
<Welcome name="Sara" />
</div>
);
}
This is the React way of doing,
You have to keep a local state (useState) and track the button click and based on the state change update the class to the container. You shouldn't directly change the DOM.
Click on the button to see the CSS is adding or not.
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [isSignUp, setSignUp] = useState(true);
return (
<div id="container" className={isSignUp ? "right-panel-active" : ""}>
<button onClick={() => setSignUp(false)}>SignIn</button>
<button onClick={() => setSignUp(true)}>SignUp</button>
//for testing the change
{isSignUp ? "right-panel-active added" : "right-panel-active removed"}
</div>
);
}
Sample working code - https://codesandbox.io/s/fragrant-http-qo6du?file=/src/App.js
No need to add click event with vanilla js, you could add an React onClick event. You forgot to return the container.
// if you use curly braces you must return the value
const container = () => {
return document.getElementById('container');
};
// or skip the curly braces
const container = () =>
document.getElementById('container');

How to get text of multiple clicked elements using useRef?

I'm trying to get useRef to console.log the text of the clicked element but it just logs the last span element of "Green" every time no matter which span element I click.
Is there a way to console.log the text for the clicked element? Perhaps there's a better hook to get the result I'm looking for?
Thanks for any help.
import React, { useRef } from "react";
export default function Hello() {
const ref = useRef(null);
function checkRef() {
console.log(ref.current.innerText);
}
return (
<div className="container">
<span ref={ref} onClick={checkRef} className="selected">
Blue
</span>
<span ref={ref} onClick={checkRef} className="selected">
Red
</span>
<span ref={ref} onClick={checkRef} className="selected">
Green
</span>
</div>
);
}
If you need a ref, put the <span>s into a separate component:
const Button = ({ text }) => {
const ref = useRef(null);
function checkRef() {
console.log(ref.current.innerText);
}
return (
<span onClick={checkRef} className='selected' ref={ref}>
{text}
</span>
);
};
export default function Hello() {
return (
<Button text='Blue' />
<Button text='Red' />
<Button text='Green' />
);
}
Though, at this point, you could also remove the ref completely and just log the text prop. This would be much more elegant if it's possible with your real code:
function checkRef() {
console.log(text);
}

Reset component into modal

I have a component that is inserted in a modal and that includes a CheckListBox. When the modal starts each time, the component is not reset. How can I do? How Force reset? I use reactjs with hooks.
How can I trigger a reset event every time the modal opens?
Thanks a lot.
const CheckList = ({title, api, color, onChange }) => {
const [items, setItems] = useState([]);
let listCheck = [];
useEffect(() => {
axiosApi.get( `${api}`).then((res)=>{
setItems(res.data);
})
}, [])
function handleClick(ev, item) {
if (ev.target.checked) {
listCheck.push(item)
onChange(listCheck);
}
else
{
listCheck = listCheck.filter(riga => {
return (riga.id !== item.id)});
onChange(listCheck);
}
}
return (
<>
<div class="card rd-card-list">
<div class="card-header">
{title}
</div>
<div class="card-content rd-card-content">
<div class="content rd-scroll">
<ul class="rd-ul">
{ items.map( (item) =>
<li class="rd-li" key={item.id}>
<label class="checkbox">
{item.description}
</label>
<input type="checkbox" onClick={(ev) => handleClick(ev, item)}/>
</li>
)
}
</ul>
</div>
</div>
</div>
</>
);
}
export default CheckList;
in my modal.js
<CheckList title="mytititle" api="/api/users" onChange={(itx) => {
formik.setFieldValue('users', itx)
} }/>
The easiest way is to not render the modal until it's open:
<div>
{modalOpen &&
<Modal open={modalOpen}>
<CheckList title="mytititle" api="/api/users" onChange={(itx) => {
formik.setFieldValue('users', itx)
} }/>
</Modal>
}
</div>
So whenever you close the modal, it will be removed from DOM, along with any data that this component had.
React life cycle events can be used to perform operation before a component can be rendered. 'constructor()' or 'componentDidMount()' can be used in class components to reset the data or any other operation before rendering the component.
Since you are using function component, you can use React hooks to mimic the life cycle events using 'useEffect()'.

Resources