I have an application with the parent component
Parent component
function App() {
const [text, setText] = useState(' ');
const outputRef = useRef();
const resetRef = useRef()
const resetBtn = ()=>{
// Reset the output field
setText('');
// Reset the button states
}
return (
<div className="resetIcon" onClick={resetBtn}>
<img src={resetIcon} alt="Reset icon for reset the game"
className='resetToggle' ref={resetRef}/>
</div>
<input type="text"
value={text}
className='display_text'
ref={outputRef}
readOnly
/>
<div className="flex">
<PaperLetter handleInnerText={handleInnerText}>teeth.</PaperLetter>
<PaperLetter handleInnerText={handleInnerText}>brush</PaperLetter>
<PaperLetter handleInnerText={handleInnerText}>my</PaperLetter>
<PaperLetter handleInnerText={handleInnerText}>i</PaperLetter>
</div>
Child Components
I want if I click on the reset button, then it should be able to change the clicked state triggering the addition and subtraction of the className
<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>
import { useState,useRef } from 'react';
export default function PaperLetter(props) {
const [click, setClick] = useState(false);
const letterRef = useRef();
const btnClicked =()=>{
//Change the className of the btn click to active
setClick(true);
//Get the value of the letter btns click
const getValue = letterRef.current.innerText;
props.handleInnerText(getValue);
}
return (
<p className={click ? 'letter clicked': 'letter'} onClick={btnClicked} ref={letterRef} >{props.children}
</p>
)
}
I want to toggle the clicked state in the child component even though the resetBtn is in the parent component
Link to the app :
I solved it by doing this.
In the App component:
Use a new useState hook for saving the clicked words:
const [clickedWords, setClickedWords] = useState([]);
Create a new method for adding a single word:
const setClickedWord = clickedWord => setClickedWords(prevState => [...prevState, clickedWord]);
Pass clickedWords and setClickedWord as props to PaperLetter.
In the PaperLetter Component:
Get the new props: const { children, clickedWords, setClickedWord } = props;
Update the btnClicked method:
const btnClicked =()=>{
setClickedWord(children)
const getValue = letterRef.current.innerText;
props.handleInnerText(getValue);
}
Update the className:
className={clickedWords.includes(props.children) ? 'letter clicked': 'letter'}
Of course there are alternatives for this, you could use a Context, you could create an array of words with ids to prevent duplicated selected words, you may create a new Intermediate component to extract this from the App components itself, etc.
Related
So this is working, input changes when I type.
const [editfield, setEdit_field] = React.useState();
function updateField(event) {
setEdit_field(event.target.value);
}
function editPost() {
setPostbody(<div><input onChange={updateField} value={editfield}></input></div>)
}
But when a put a default value in the useState it doesnt work anymore
const [editfield, setEdit_field] = React.useState(post.body);
function updateField(event) {
setEdit_field(event.target.value);
}
function editPost() {
setPostbody(<div><input onChange={updateField} value={editfield}></input></div>)
}
Access code here: https://codesandbox.io/s/brt7ok
You were setting JSX inside the state, that might be the issue, I have created a codesandbox demo which will help you in conditional Rendering
DEMO
You are rendering that function so when state will updated it re-run that function and resetting the value.
You can use below approach.
Take one state which represents the field is editable or not. And add condition with input component that it should only render when field is editable.
For example,
const [isEditable, setIsEditable] = useState(false);
<button onClick={() => setIsEditable(!isEditable)}>edit</button>
isEditable && (
<div>
<input onChange={updateField} value={editfield} />
</div>
)
For more idea, just put console before return. You will get idea.
Hope this helps :)
import React, { useState } from "react";
export default function App() {
let body = "hello";
const [editfield, setEditfield] = useState(body);
const [visible, setVisible] = useState(false);
function updateField(event) {
setEditfield(event.target.value);
}
function editPost() {
setVisible(true);
}
return (
<div>
<div>{visible?<div>
<input onChange={updateField} value={editfield}/>
</div>:body}</div>
<div>
<button onClick={editPost}>edit</button>
</div>
</div>
);
}
I am learning ReactJs, and building a sample project. I am facing a problem while pushing the items to the array. My application has a list(10 items) and I am trying to push props to an array; But I am facing the below issues:
On click of "Choose" button, first time item does not push into the array, but it pushes on the second click.
When I click on the other li item the first item pushed to the array is deleted and the second item pushes to it.
I am trying to solve this for the last few hours, I tried other solutions on this platform but nothing works. What I am doing wrong.
import React, {useState} from 'react';
const MItem = (props)=>{
const [nameList, setName] = useState([]);
const NameHandler = ()=>{
setName(nameList => [...nameList, props]);
}
return (
<div>
<div>
<h3>{props.title}</h3>
<img src={props.pic} />
<p>{props.year}</p>
</div>
<div>
<button onClick={NameHandler}> Choose </button>
</div>
</div>
)
}
export default MItem;
Lets assume, you sent test using the attribute value as below
<MItem value="test">
Now you should use props.value not props
setName(nameList => [...nameList, props.value]);
Here is your example:
import React, {useState} from 'react';
const MItem = (props)=>{
const [nameList, setName] = useState([]);
const NameHandler = ()=>{
setName(nameList => [...nameList, props.value]);
}
return (
<button onClick={NameHandler}> Choose </button>
)
}
export default MItem;
More detail
you don't need to pass a function to setName you can just do.
Based on your comments
const NameHandler = ()=>{
const item = {title: props.title, pic: props.pic}
setName([...nameList, item]);
}
I have a simple example
function Node() {
const [hidden, setHidden] = useState(true);
const inputRef = useRef(null)
console.log(inputRef);
return (
<div>
{!hidden && <h2 ref={inputRef}>Hello World</h2>}
{hidden && <button onClick={() => setHidden(false)}>Show Child</button>}
</div>
)
}
Upon clicking the button, I would expect that the h2 DOM element is attached to my ref. However, I found that the ref.current is still null upon logging, but if I expand the object, it contains the DOM node.
How am I supposed to access the DOM element via my ref? At the time I want to reference it, for example inputRef.current.getBoundingClientRect(), it's always shown as null.
Your help is much appreciated!
You are trying to use the ref in the render phase, but the ref will be populate once React paint the screen, in the commit phase.
So, call it in a useEffect or useLayoutEffect
// run synchronously after all DOM mutations
React.useLayoutEffect(() => {
// do something with inputRef
}, [])
Your ref is not initialize when setHidden set to false if you want to use it you need some interactions like this
import React, { useRef, useState, useEffect } from 'react';
function App() {
const [hidden, setHidden] = useState(true);
const inputRef = useRef(null)
console.log(inputRef);
const handleChange=()=>{
console.log(inputRef);
}
useEffect(()=>{
console.log(inputRef);
},[hidden])
return (
<div>
<input onChange ={handleChange}></input>
{!hidden && <h2 ref={inputRef}>Hello World</h2>}
{hidden && <button onClick={() => setHidden(false)}>Show Child</button>}
</div>
)
}
export default App;
I have been looking around a method to correctly focus and select a checkbox in React code.
The methods focus() and select() that I'm using in the example below are not working :
import React, { useRef } from "react";
export const HelloWorld = () => {
const checkboxref = useRef(null);
const handleOnClick = () => {
checkboxref.current.focus();
checkboxref.current.select();
};
return (
<div>
<button onClick={handleOnClick}>Focus</button>
<input type="checkbox" ref={checkboxref} />
</div>
);
};
When I click on the button, my checkbox is not focused and not selected...
Any solution please ?
Thank you so much.
You don't need to create a separate function to handle onChange event
const checkboxref = useRef(null);
You can simply get the current value of the checkbox with:
checkboxref.current.checked
// which returns a boolean
use this one it might help you. here I am using createRef instead of useRef and also uses the callback hook which ensures the availability of ref when you click the button.
import React,{createRef, useCallback} from 'react';
export const HelloWorld = () => {
const checkboxref = createRef();
const handleOnClick = useCallback(() => {
const node = checkboxref.current;
if(node){
node.focus();
node.select();
}
}, [checkboxref]);
return (
<div>
<button onClick={handleOnClick}>Focus</button>
<input type="checkbox" ref={checkboxref} />
</div>
);
};
The select methods selects text in elements such as text inputs and text areas, so I'm not sure what effect you expect it to have on the checkbox. As for focus, it can focus, but again, there is not much you can do with a focused checkbox. I can only think of styling it https://jsfiddle.net/4howanL2/1/
I have a React button component with onClick handler and its state - stating whether it was opened on click. If I render two of such components in a wrapper container, and I click on one of them, both buttons update the state. How should I handle the state, so that only one of the buttons updates without using ids?
import React, {useState} from 'react';
const Button = (props) => {
const [open, setOpen] = useState(false);
const text = open ? 'Open' : 'Closed';
const toggleButton = () => { setOpen(!open) };
return (
<button onClick={toggleButton}>{text}</button>
)
}
// parent component
import React from 'react';
import Button from './Button'
const ButtonsWrapper = () => {
return (
<div>
<Button />
<Button />
</div>
)
}
I also tried reversing the logic and putting the state in a wrapper component, and then passing the onClick handler as a props to a button, but the sitation is the same. They both change the state at the same time when one of them is clicked.
I am using React Hooks.
My understanding is that you are saying that when you click one button both buttons seems to have their state updated, but you only want the clicked button to update its state.
(i.e. if you click Button A only that button will show 'Open' as its text, Button B will continue to show closed)
If the above is right, then your code should already do the correct thing. If it doesn't then you might have a bug elsewhere that would cause this.
If however you want to click one button and BOTH should switch state then you could achieve this by keeping track of the state in the parent component:
import React, {useState} from 'react';
const Button = (props) => {
const text = props.isOpen ? 'Open' : 'Closed';
const handleClick = () => {
// do some stuff you want each button to do individually
.....
props.onClick()
}
return (
<button onClick={handleClick}>{text}</button>
)
}
// parent component
import React from 'react';
import Button from './Button'
const ButtonsWrapper = () => {
const [buttonState, setButtonState] = useState(false)
return (
<div>
<Button onClick={() => setButtonState(!buttonState)} isOpen={buttonState} />
<Button onClick={() => setButtonState(!buttonState)} isOpen={buttonState} />
</div>
)
}