I have an exercise where I have to make an input and a button. When I click the button, there has to be created a div/span below, which prints the text which is in input. If I change the text in input, it has to be refreshed in that div/span only when I click the button again. I tried to do it with makeDiv function, but it doesn't do anything. I made console.log(event.target.value) and it handles the text which is in input, but nothing happens then.
My code:
import {useState} from "react"
function About() {
const [initialValue,setInitialValue] = useState('')
const handleValueChange = (event) => {
console.log(event.target.value)
setInitialValue(event.target.value)
}
const makeDiv = () => {
return (<div>Value: {initialValue}</div>)
}
return(
<div>
<button onClick={makeDiv}>click me</button>
<div><input type="text" onChange={handleValueChange} /></div>
</div>
)
}
export default About
edit:
What if I wanted to make an exercise very similar to that, but now, I have to add <li>text in input</li> to <ul> each time I click the button. So when I click the button, I add one li to the list, I tried like this, but it doesn't compile:
import {useState} from "react"
function About() {
const [initialValueLastExercise, setInitialValueLastExercise] = useState([])
const [ValueLE, setValueLE] = useState([])
const handleValueChangeLE = (event) => {
console.log(event.target.value)
setInitialValueLastExercise([...initialValueLastExercise, event.target.value])
}
const showListWithText = () => {
setShouldDisplayText(true)
setValueLE(initialValueLastExercise)
}
return(
<div>
<button onClick={showListWithText}>click me to refresh the list</button>
<div><input type="text" onChange={handleValueChangeLE} /></div>
{shouldDisplayText && <div><ul>
{
for (let i =0; i<initialValueLastExercise.length; i++) {
<li>{initialValueLastExercise[i]}</li>
}
}</div></ul>}
</div>
)
}
export default About
This will refresh the value of the div on button click only as you have mentioned in the question.
import {useState} from "react"
function App() {
const [initialValue,setInitialValue] = useState('')
const [displayText, setDisplayText] = useState(false)
const [Value,setValue] = useState('')
const handleValueChange = (event) => {
setInitialValue(event.target.value)
}
const showText = () => {setDisplayText(true)
setValue(initialValue)};
return(
<div>
<button onClick={showText}>click me</button>
<div><input type="text" onChange={handleValueChange} /></div>
{displayText && <div>Value: {Value}</div>}
</div>
)
}
export default App
Solution for the Edited Question.
import {useState} from "react"
function App() {
const [initialValue,setInitialValue] = useState('')
const [displayText, setDisplayText] = useState(false)
const [Value,setValue] = useState([])
const handleValueChange = (event) => {
setInitialValue(event.target.value)
}
const showText = () => {setDisplayText(true)
setValue([...Value,initialValue])};
return(
<div>
<button onClick={showText}>click me</button>
<div><input type="text" onChange={handleValueChange} /></div>
<ul>{displayText && Value.length > 0 &&
Value.map((i) => {
return <li>Value: {i}</li>
})}</ul>
</div>
)
}
export default App
One way to do it is to create another state variable which indicates whether the div you're trying to make should be displayed and then render it conditionally. Something like
import {useState} from "react"
function About() {
const [initialValue,setInitialValue] = useState('')
const [shouldDisplayText, setShouldDisplayText] = useState(false)
const handleValueChange = (event) => {
console.log(event.target.value)
setInitialValue(event.target.value)
}
const showDivWithText = () => setShouldDisplayText(true);
return(
<div>
<button onClick={showDivWithText}>click me</button>
<div><input type="text" onChange={handleValueChange} /></div>
{shouldDisplayText && <div>Value: {initialValue}</div>}
</div>
)
}
export default About
Your approach is fundamentally wrong.
You should:
Store all the data about the component in the state
Render the output based on the state
So:
You need two state variables:
currentInputValue (because you need to store the value to display and edit in input)
selectedValue (because you need to store the value to be displayed in the div)
When onChange fires, update currentInputValue with the value of the input.
When onClick fires, update selectedValue with the current value of currentInputValue
When you return your data, include something like:
{selectedValue && <div>{selectedValue}</div>}
… to output a div containing the selected value only if there is a truthy value (the default empty string isn't truthy so the div won't be output then)
1st possibility - close to your code source
Don't forget to bind initialValue to the input and to add makeDiv content to the JSX :
return (
<div>
<button onClick={makeDiv}>click me</button>
<input type="text" onChange={handleValueChange} value={initialValue} />
{makeDiv}
</div>
)
2nd possibility - with another approach
return (
<div>
<button onClick={makeDiv}>click me</button>
<input type="text" onChange={handleValueChange} value={initialValue} />
{initialValue && <div>{initialValue}</div>}
</div>
)
Related
I am trying to make a simple react app that displays radio input for each 'hero' from a list of heroes and if the user checks, the hero's name will be displayed as the favorite hero. But the problem is on my local machine to check a hero I need to double click that radio input. How can I check a hero with a single click?
Code of the app.js file is given below:
import React, { useState } from "react";
import "./App.css";
function App() {
const [heros, setHeros] = useState([
"Superman",
"Batman",
"Antman",
"Robocop",
]);
const [selected, setSelected] = useState(null);
const handleChange = (e) => {
e.preventDefault();
setSelected(e.target.value);
console.log(e.target.checked);
};
return (
<div>
<h1>Select Your Favorite Hero</h1>
<form onChange={handleChange}>
{heros.map((hero, index) => (
<div key={index}>
<input
type="radio"
name="hero"
id={hero}
value={hero}
/>
<label htmlFor="{hero}">{hero}</label>
<br />
</div>
))}
</form>
<div>
<p>Your super hero is: {selected}</p>
</div>
</div>
);
}
export default App;
Remove e.preventDefault() inside handleChange function. Function will be like this one.
const handleChange = (e) => {
setSelected(e.target.value);
console.log(e.target.checked);
};
First, select the button with #btn id, output element with the #output id, and all the radio buttons with the name heros
const btn = document.querySelector('#btn');
const output = document.querySelector('#output');
const radioButtons = document.querySelectorAll('input[name="heros"]');
This is my Add_Blog.js file
import React, { useState } from "react";
function AddBlogs() {
const ADD = () => {
return (
<div>
<label>Topic</label>
<input></input>
<label>Content</label>
<textarea></textarea>
<button type="button" onClick={deleteContent} value={state.length}> Delete</button>
</div>
);
}
const [state, setState] = useState([<ADD key="first"></ADD>]);
const addblog = () => {
setState([...state, <ADD key={state.length}></ADD>])
}
const deleteContent = (event, key) => {
setState([...state, state.splice(event.target.value, 1)]);
}
return (
<div>
<form>
<div>
<label>Add Title</label>
<input></input>
</div>
<div>
{
state
}
</div>
<div>
<button type="button" onClick={addblog}>Add another topic</button>
</div>
<input type="submit" value="publish"></input>
</form>
</div>
);
}
export default AddBlogs;
My expectation from this code is to remove component left of delete button when I press that delete button. But when I press delete button it removes that component and every components below it.
Any solution for this?
It does not work because you are using the splice method wrong. It returns the deleted value.
You can change your deleteContent function like this:
const deleteContent = (event, key) => {
let indexToRemove = Number(event.target.value);
setState((prevState) => prevState.filter((elem, index) => index !== indexToRemove));
}
That will be enough for the program to work as expected
I am learning React and I can't seem to figure out how to remove an item from an array. I have tried couple of ways but it either removes the entire array or more than one item in the array so I can't find any working solution. Here is my code:
App.js:
import React, { useState } from 'react';
import Education from './Education';
export default function App() {
const [educationArray, setEducationArray] = useState([]);
const handleDeleteEduItem =(id)=>{
const eduArrayToSplice = [...educationArray]
const newEduArray = eduArrayToSplice.splice(id, 1)
setEducationArray(newEduArray)
console.log(id)
}
return (
<div className="App">
<div className="edit-mode">
<h4>Education</h4>
<button onClick={()=>{setEducationArray([...educationArray, <Education id={educationArray.length} handleDeleteButton={handleDeleteEduItem}/>])}}>add new</button>
{educationArray.map((eduItem, i)=><div className="eduItem" key={i}>{eduItem}</div>)}
</div>
</div>
);
}
And the functional component:
import React, { useState} from 'react';
function Education(props)
{
const [schoolName, setSchoolName] = useState('');
const [major, setMajor] = useState('');
const [studyFrom, setStudyFrom] = useState('')
const [studyTo, setStudyTo] = useState('');
const [degree, setDegree] = useState('');
const [displayEducationSection, setEducationSection] = useState(false)
const changeSchoolName = (e) => {
setSchoolName(e.target.value);
};
const changeMajor = (e) => {
setMajor(e.target.value);
};
const changeStudyFrom =(e)=> {
setStudyFrom(e.target.value);
};
const changeStudyTo =(e)=> {
setStudyTo(e.target.value)
};
const changeDegree =(e) => {
setDegree(e.target.value);
};
const flipEducationSection =()=> {
setEducationSection(!displayEducationSection)
};
return(
<div className="education-section">
{displayEducationSection ?
<div>
<p>School Name: {schoolName}</p>
<p>Major: {major}</p>
<p>from: {studyFrom}</p>
<p>to: {studyTo}</p>
<p>Degree: {degree}</p>
</div>
:
<form onSubmit={(e)=>e.preventDefault()} className="education-form">
<label>
School Name:<input value={schoolName} onChange={changeSchoolName} />
</label>
<label>
Major:<input value={major} onChange={changeMajor} />
</label>
<label>
From:<input value={studyFrom} onChange={changeStudyFrom} />
</label>
<label>
To:<input value={studyTo} onChange={changeStudyTo} />
</label>
<label>
Degree:<input value={degree} onChange={changeDegree} />
</label>
</form>}
<button onClick={flipEducationSection}>{displayEducationSection ? 'edit' : 'save'}</button>
<button onClick={()=>props.handleDeleteButton(props.id)}>delete</button>
</div>
)
}
export default Education;
I've also used the following function to try to remove an item from the array, but it doesn't remove the clicked item but removes all items that come after it:
const handleDeleteEduItem =(id)=>{
const newEduArray = educationArray.filter((item)=>educationArray[item] !== id)
setEducationArray(newEduArray)
console.log(educationArray)
}
I think you don't want to filter directly the state. What you could do instead is:
setEducationArray((cv) => cv.filter((e) => e.id !== id ))
This way you get to access the current value in your educationArray state (cv), and filter that to get all elements where the e.id is not equal to the id you have given to your id.
Edit:
To be fair, I'm not sure how your array eventually looks like. But if it was an array of objects, with each object having its own id. Then I would suggest the thing I wrote above.
you can not directly update the state with using same memory location.
you have to create new memory to updated array and then update the component state. you will see quickly changes on UI.
else this function will help you to remove single item from array.
you have to
ensure that your id should be unique for each item.
const handleDeleteEduItem =(id)=>{
const eduArrayToSplice = [...educationArray.filter(item)=>item.id!==id)]
setEducationArray(newEduArray)
console.log(id)
}
I'm trying to remove a CSS class from a specific item when clicking on that item's button. Removing the CSS class will make a menu appear. How would I go about doing this with React? Here's the code.
import "./Homepage.css"
import React, { useState, useEffect, useRef } from "react"
// import { FontAwesomeIcon } from "#fortawesome/react-fontawesome"
// import { faArrowDown } from "#fortawesome/free-solid-svg-icons"
import { Link } from "react-router-dom"
import useFetch from "./useFetch"
import Axios from "axios"
export default function Homepage() {
const [body, setBody] = useState("")
const [sortedData, setSortedData] = useState("")
const [data, setData] = useState("")
const [css, setCss] = useState("")
const [flash, setFlash] = useState(null)
const posts = useFetch("http://localhost:5000/api/data")
const firstRender = useRef(true)
useEffect(() => {
let test = JSON.parse(window.localStorage.getItem("user"))
console.log(test)
setData(posts)
}, [posts])
useEffect(() => {
if (firstRender.current) {
firstRender.current = false
return
}
data.sort(function (a, b) {
return new Date(b.date) - new Date(a.date)
})
setSortedData(data)
}, [data])
const handleSubmit = (e) => {
e.preventDefault()
Axios.post("http://localhost:5000/api/react-create-post", { text: body }, { withCredentials: true })
.then((res) => {
setSortedData((prevArray) => [res.data.post, ...prevArray])
setFlash("Successfully created post.")
setCss("success-msg")
setBody("")
})
.catch((err) => {
setCss("error-msg")
setFlash("Field cannot be left blank.")
})
}
const handleClick = (e) => {
e.preventDefault()
e.target.parentElement.children[1]
}
return (
<div>
<center>
<div className="create-container">
<div className="posts-title">Create Post</div>
<form id="theForm" onSubmit={(e) => handleSubmit(e)}>
<textarea onChange={(e) => setBody(e.target.value)} value={`${body}`} id="theInput" className="post-input" name="text" type="text"></textarea>
<button className="submit-btn">POST</button>
</form>
</div>
<div id="postsContainer" className="posts-container">
<div className="posts-title">Latest Posts</div>
{flash ? <div className={css}>{flash}</div> : console.log()}
<div id="postInput">
{sortedData &&
sortedData.map((item) => {
return (
<div className="post-container" key={item._id}>
<Link className="a" to={`/user/${item.author}`}>
<h3 className="author">{item.author}</h3>
</Link>
<div className="date">{item.date.toLocaleString()}</div>
<div className="options-cont">
<button onClick={(e) => handleClick(e)} id="optionsBtn" className="options-btn">
<i className="fas fa-ellipsis-v"></i>
</button>
<button data-author={`${item.author}`} data-id={`${item._id}`} data-text={`${item.body}`} id="editBtn" className="edit inside-btn invisible">
Edit
</button>
<button data-author={`${item.author}`} data-id={`${item._id}`} id="deleteBtn" className="delete inside-btn invisible">
Delete
</button>
<br></br>
</div>
<p className="body-text">{item.body}</p>
</div>
)
})}
</div>
</div>
</center>
</div>
)
}
As far as I'm concerned using state as the className would remove or alter the CSS of each item in the "sortedData" array and make the menus for all items appear. I only want the menu for one of the items to appear.
As pilchard said, you probably want to make each of those its own component with its own "showing" state, or at least "showing" prop.
As far as I'm concerned using state as the className would remove or alter the CSS of each item in the "sortedData" array and make the menus for all items appear. I only want the menu for one of the items to appear.
That would be true if you used a single flag in state. But instead, use a set of flags, one flag for each menu, perhaps keyed by item._id.
Assuming you don't do the refactoring pilchard (and I) suggest:
You haven't shown us enough code for me to know whether you're using class components or function components, so I'm going to guess function components with hooks. If so, the initial state would be:
const [showing, setShowing] = useState(new Set());
Then when rendering, you'd assign the class:
<theElement className={showing.has(item._id) ? "class-if-any-to-show-it" : "class-if-any-to-not-show-it" ...
To toggle, in the button pass the ID:
<button onClick={(e) => handleClick(e, item._id)}
and then update state as appropriate:
const handleClick = (e, id) => {
e.preventDefault()
setShowing(showing => {
showing = new Set(showing);
if (showing.has(id)) {
showing.delete(id);
} else {
showing.add(id);
}
return showing;
});
};
Good afternoon everyone.
I have a dropdown with two input fields inside. Name and Price.
I would like to display the name and price after I click Set button that it appears in the same dropdown but on top of input fields.
Here is how it looks in my app currently, I enter name and price by myself.
As you can see in a first field there is a name and in the second there is a number and I wan't to store it under Price Alert History after clicking Set button.
Here is how I wish it will look. It's just an example which was made in photoshop. The main thing that I want to see name and price on top of input field.
CODE HERE
import React from "react";
import { Button} from "react-bootstrap";
const symbols = [
"ADABTC",
"AIONBTC",
"ALGOBTC",
"ARDRBTC",
"KAVABTC",
"ETHBTC",
"ETCBTC"
];
function PriceTriggerField() {
const [searchTerm, setSearchTerm] = React.useState("");
const [searchSymbol, setSearchSymbol] = React.useState([]);
const handleChangeTerm = event => {
setSearchTerm(event.target.value);
};
const handleChangeSymbol = event => {
setSearchSymbol(event.target.value);
};
React.useEffect(() => {
const results = symbols.filter(symbols =>
symbols.toUpperCase().includes(searchTerm)
);
setSearchSymbol(results);
}, [searchTerm]);
return (
<div className="App">
<h6>Price Alert History</h6>
<input
type="text"
placeholder="Symbol"
value={searchTerm}
onChange={handleChangeTerm}
/>
<input
type="number"
placeholder="Price"
/>
{
searchTerm.length > 0 && searchSymbol.map(item => <li onClick={(() => setSearchTerm(item) )}>{item}</li>)
}
<Button variant="secondary">Set</Button>
</div>
);
}
export default PriceTriggerField;
this is just a simple example with only one variable, but of course, you can do that for as many variables as you wish.
import React, { useState } from "react";
export default function App() {
const [name, setName] = useState(null);
let tmpName;
const onChange = e => {
tmpName = e.target.value;
}
return (
<div className="App">
<input onChange={onChange} />
<button onClick={() => setName(tmpName)}>set</button>
name: {name}
</div>
);
}