How to get text of multiple clicked elements using useRef? - reactjs

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

Related

How to get children div via parent useRef in 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>

Trigger events upwards for custom components

I have a custom made component called CoolButton.
If I involve the component in another component like below, I'd somehow like to trigger the onClick-event, just like if it was a normal button.
A second question (not as important), is if it's possible to access the Press Me-value which was passed down the the CoolButton-component, in the child/CoolButton-Component. I'd much rather want Press Me to be dislayed instead of I'm button
export default function Home() {
[timesClicked, setTimesClicked] = useState(0)
return (
<div className="home">
<h1>Click the button!</h1>
<div>The CoolButton has been clicked {timesClicked} times!</div>
<CoolButton onClick={() => setTimesClicked(timesClicked + 1)}>Press Me</CoolButton>
</div>
);
}
export default function CoolButton() {
return (
<div className="cool_button">
<button>I'm button</button>
</div>
);
}
You are passing onClick as a prop to CoolButton component. Unless you use that prop in your component, it would not make any difference. Regarding your second question, if you would like wrap your component around some content, you should provide children in the component. Something like this:
export default function Home() {
[timesClicked, setTimesClicked] = useState(0)
return (
<div className="home">
<h1>Click the button!</h1>
<div>The CoolButton has been clicked {timesClicked} times!</div>
<CoolButton onClick={() => setTimesClicked(timesClicked + 1)}>Press Me</CoolButton>
</div>
);
}
export default function CoolButton(props) {
return (
<div className="cool_button">
<button onClick={props.onClick}>{props.children}</button>
</div>
);
}
You should pass the state variables down to the button and call them on the onClick event of the <button>.
You can pass a custom title to the button as prop as well
export default function Home() {
const [timesClicked, setTimesClicked] = useState(0);
return (
<div className='home'>
<h1>Click the button!</h1>
<div>The CoolButton has been clicked {timesClicked} times!</div>
<CoolButton
setTimesClicked={setTimesClicked}
title='Press Me'
/>
</div>
);
}
export default function CoolButton({ title, setTimesClicked }) {
return (
<div className='cool_button'>
<button onClick={() => setTimesClicked((oldTimes) => oldTimes + 1)}>{title}</button>
</div>
);
}

i`m a React beginner and function setState() is not working, and i need your help guys

I'm currently studying React and tried to make To-do list. Below is the source code.
I want to change the state "display" of the Frame component by clicking the button. I found out that the handler I addEventListener'd to the button element worked, but the state display never changed and even there are no errors on console. Why?
Frame Component
class Frame extends Component {
state = {
list: ["왜", "안돼냐"],
display: "before!!!",
};
registerHandler = () => {
this.setState = {
display: "after",
};
};
render() {
return (
<div className="frame">
<h1>To-Do-Lists</h1>
<h2>{this.state.display}</h2>
<div className="wrapper">
<Lists list={this.state.list} />
</div>
<div className="action">
<Button name="Register" onClick={this.registerHandler} />
</div>
</div>
);
}
}
export default Frame;
Button 관련 부분
import React, { Fragment } from "react";
const button = (props) => {
return (
<Fragment>
<button onClick={props.onClick} className="action button">
{props.name}
</button>
</Fragment>
);
};
export default button;
Mby you trying to set this.setState equal to something, try use it like this this.setState({})

Set focus in input on clicking div

I have the following HTML inside function component
<div>
<input />
<div>
<div>
<input />
<div>
<div>
<input />
<div>
I am not finding any easy way to do this...
I have gone some article saying to store input ref, but here I have confusion about how to store inputref using id or something...
I am totally lost so unable to proceed
Please help
Thanks
you can set id to input and use input to focus on input
example
import React from "react";
import "./styles.css";
export default function App() {
return (
<div className="App">
<div
className='inputCon'
onClick={()=>{
const input = document.getElementById("input");
input.focus()
}}>
<input
placeholder="click on green area"
id="input"
/>
</div>
</div>
);
}
The use of the useRef-Hook is explained in great detail here.
But basically you create a ref and in your onClick you add the call .focus() on it like this:
function CustomTextInput(props) {
// textInput must be declared here so the ref can refer to it
const textInput = useRef(null);
function handleClick() {
textInput.current.focus();
}
return (
<div>
<input
type="text"
ref={textInput} />
<input
type="button"
value="Focus the text input"
onClick={handleClick}
/>
</div>
);
}
You don't necessarily need a ref for that. The following code hooks up directly into the click event, find the closest input child, and focus on it. Click anywhere in the orange zone to focus on the input:
const MyComponent = () => {
const onClick = evt => {
evt.target.querySelector('input').focus();
};
return (<div onClick={onClick}><input/></div>);
}
ReactDOM.render((<MyComponent/>), document.body);
div {
padding: 1em;
background-color: coral;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

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