I have a React form with dynamic input fields that a user can add and remove input fields. When i submit the form, i log the values from each input in an array. The problem is that i can't type continuously in a input. When i type in input, i can type only one character and it focus out. How can i fix it?
CodeSandbox
App.js
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [fields, setFields] = useState([""]);
function handleChange(i, event) {
const values = [...fields];
values[i] = event.target.value;
setFields(values);
}
function handleAdd() {
const values = [...fields];
values.push("");
setFields(values);
}
function handleRemove(i) {
const values = [...fields];
values.splice(i, 1);
setFields(values);
}
function submitHandler(event) {
event.preventDefault();
console.log(fields);
}
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<form onSubmit={submitHandler}>
<button type="button" onClick={() => handleAdd()}>
Add Input
</button>
{fields.map((field, idx) => {
return (
<div key={`${field}-${idx}`}>
<input
type="text"
placeholder="Enter text"
value={field || ""}
onChange={(e) => handleChange(idx, e)}
/>
<button type="button" onClick={() => handleRemove(idx)}>
X
</button>
</div>
);
})}
<button className="margin-top" type="submit">
Submit
</button>
</form>
</div>
);
}
export default App;
Replace your code with this
<div key={`${"asdf"}-${idx}`}>
<input
type="text"
placeholder="Enter text"
value={field || ""}
onChange={(e) => handleChange(idx, e)}
/>
<button type="button" onClick={() => handleRemove(idx)}>
X
</button>
</div>
i have used a third party debounce , you can choose anything you want
code
import React, { useState } from "react";
import AwesomeDebouncePromise from "awesome-debounce-promise";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [fields, setFields] = useState([""]);
function handleChange(i, event) {
const values = [...fields];
values[i] = event.target.value;
setFields(values);
}
function handleAdd() {
const values = [...fields];
values.push("");
setFields(values);
}
function handleRemove(i) {
const values = [...fields];
values.splice(i, 1);
setFields(values);
}
const searchAPIDebounced = AwesomeDebouncePromise((event) => {
console.log(fields);
}, 100);
const submitHandler = async (event) => {
event.preventDefault();
const result = await searchAPIDebounced(event);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<form onSubmit={submitHandler}>
<button type="button" onClick={() => handleAdd()}>
Add Input
</button>
{fields.map((field, idx) => {
return (
<div key={`${idx}`}>
<input
type="text"
placeholder="Enter text"
value={field || ""}
onChange={(e) => handleChange(idx, e)}
/>
<button type="button" onClick={() => handleRemove(idx)}>
X
</button>
</div>
);
})}
<button className="margin-top" type="submit">
Submit
</button>
</form>
</div>
);
}
export default App;
Related
I'm trying to put input value into json file, but submit button doesn't work, can you help me with it?
import PcosData from "/data/pcos.json";
import {useEffect} from "react";
import { useState } from "react";
export default function adminPcos() {
// const CreateMePanel = () => {
const [title, setTitle] = useState(PcosData["pcos-first"].title);
const [time, setTime] = useState(PcosData["pcos-first"].time);
const handleSubmit = (e) => {
PcosData["pcos-first"].title = title;
PcosData["pcos-first"].time = time;
}
return (
<div>
<h1>hello world</h1>
{PcosData["pcos-first"].map((pcosdata) => (
<form onSubmit={handleSubmit} key={ pcosdata.id } method="post">
<input type="text" name={title} defaultValue={pcosdata.title} onChange={(e) => setTitle({text: e.target.value})}/>
<input type="text" name={time} defaultValue={pcosdata.time} onChange={(e) => setTime({text: e.target.value})}/>
<input type="submit" value="submit"/>
</form>
))}
</div>
)
}
i checked all of the functions, variables, but didn't find any errors
I just want to know, how to show a anything in a HTML body when the button is clicked. Is there anythin like echo in php
this is my appTodo.js code....
import React, { useState } from 'react'
export default function AddTodo() {
const [input, setInput] = useState("");
const onChange = (e) => {
setInput(e.target.value)
}
const handleOnClick = () => {
console.log(input)
setInput("")
}
return (
<div className='container my-3 col-6'>
<form>
<input className="form-control" onChange={onChange} type="text" placeholder="What to do?" value={input} />
<button id='addbtn' onClick={handleOnClick} type="button" className="btn btn-dark my-3">Add</button>
</form>
</div>
)
}
Just you need to create one variable to keep the state of the visibility of the div.
import React, { useState } from 'react'
export default function AddTodo() {
const [input, setInput] = useState("");
const [divVisibility, setDivVisibility] = useState(false);
const onChange = (e) => {
setInput(e.target.value)
}
const handleOnClick = () => {
setInput("")
setDivVisibility(true)
}
return (
<div className='container my-3 col-6'>
<form>
<input className="form-control" onChange={onChange} type="text" placeholder="What to do?" value={input} />
<button id='addbtn' onClick={handleOnClick} type="button" className="btn btn-dark my-3">Add</button>
</form>
{divVisibility &&
<div>
Your content
</div>
}
</div>
)
}
This code makes a state that can be changes between true and false by clicking the button. When false "componenet" = null, and when true "component" = (your component).
const [visible, setVisible] = useState(false);
function makeVisible() {
if(visible === false){
setVisible(true)
} else setVisible(false);
}
const component = visible == true ? <h1>SHOWN</h1> : null;
const buttonString = visible == true? "UnShow" : "Show"
return (
<div className="App">
<h1>Hello World!</h1>
{component}
<button onClick={makeVisible} >{buttonString}</button>
</div>
);
}
I have here 2 JS files here (React JS) and a small error. The idea is that this application is an TodoList and an element is created by clicking on the respective button. It works well but every time I add a new element, the color of the li stays the same. It doesn't move after that LI.
App.js
import React, { useState, useRef } from "react"
import ItemToDo from "./ItemToDo"
import "./style.scss"
export default function App() {
const [items, setItems] = useState([])
const [currentMap, setMap] = useState()
const inputRef = useRef()
const addElement = () => {
if (inputRef.current.value === "") {
alert("Please enter something...")
} else {
items.unshift(inputRef.current.value)
setItems(items)
console.log(items)
inputRef.current.value = ""
updateMap()
}
}
const updateMap = () => {
setMap(items.map((item, key) => <ItemToDo key={key} item={item} removeElement={() => removeElement(key)} />))
}
const removeElement = (index) => {
delete items[index]
updateMap()
}
const handleKey = (e) => {
if (e.key === 'Enter') {
addElement()
}
}
return (
<>
<h1>ToDo List</h1>
<input type="text" placeholder="Name here" ref={inputRef} id="elementName" onKeyDown={handleKey} autoFocus />
<input type="button" value="Add Item" id="submit" onClick={addElement} />
<div>
<ul>
{currentMap}
</ul>
</div>
</>
)
}
and ItemToDo.js
import React, {useState} from "react"
export default function ItemToDo({item, removeElement}) {
const [color, setColor] = useState(true)
const setBackground = () => {
setColor(false)
}
return (
<li style={{backgroundColor: color ? "green" : "red"}}>
<span>{item}</span>
<input type="button" value="Delete" onClick={removeElement} />
<input type="button" value="Done!" onClick={() => setBackground()} />
</li>
)
}
And I want to fix this bug... Basically if I add a new element the red color stays there.
Thanks in advance for any idea!
I have a form component in React that I use to send data to a pg database.
This is my form script :
import bodyParser from 'body-parser';
import React, { Fragment, useState } from 'react';
import RatingStar from '../components/rating'
const InputData = () => {
const [name, setName] = useState('')
const [rating, setRating] = useState('')
const onSubmitForm = async(e) => {
e.preventDefault();
try {
const payload = {
name,
rating
}
const response = await fetch("path", {
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify(payload)
});
window.location = "/";
} catch (error) {
console.log(error.message);
}
}
return(
<Fragment>
<div className="container">
<h1 className="text-center mt-5">RATE</h1>
<form className="mt-5" onSubmit={onSubmitForm}>
<div className="form-group">
<input
placeholder="Name"
type='text'
className='form-control'
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
<div className="form-group">
<div>
<RatingStar
value={}
/>
</div>
</div>
<div className="d-flex justify-content-center">
<button type="submit" className="d-flex btn btn-primary">Submit</button>
</div>
</form>
</div>
</Fragment>
);
}
export default InputData;
And this is my rating component :
import React, { useState } from 'react';
import { render } from 'react-dom';
import ReactStars from 'react-rating-stars-component'
import './style.css'
export default function RatingStar() {
const [rating, setRating] = useState("")
const secondExample = {
size: 50,
count: 5,
color: "black",
activeColor: "yellow",
value: 0,
a11y: true,
isHalf: true,
emptyIcon: <i className="far fa-star" />,
halfIcon: <i className="fa fa-star-half-alt" />,
filledIcon: <i className="fa fa-star" />,
onChange: (newValue) => {
console.log(`Example 2: new value is ${newValue}`);
setRating(newValue) // my try
}
};
return (
<div className="starComponent">
<ReactStars {...secondExample}
/>
</div>
);
}
So I was wondering how I could use newValue in the form component.
For now I tried using useState in the rating component but I can't access it from the form component to use it in my paylod.
Instead of keeping same state (i.e rating value) in two components, keep it in form component and pass it as prop to the Rating component.
Rating component will notify the parent(Form) component whenever the value gets changed by calling a function. This is called Lifting state up.
Here is the code for Rating component which gets rating and onRatingChange props from the form component. onRatingChange will be called with newValue from inside onChange function.
export default function RatingStar({ rating, onRatingChange }) {
const secondExample = {
size: 50,
count: 5,
color: "black",
activeColor: "yellow",
value: rating, // pass rating value here
a11y: true,
isHalf: true,
emptyIcon: <i className="far fa-star" />,
halfIcon: <i className="fa fa-star-half-alt" />,
filledIcon: <i className="fa fa-star" />,
onChange: (newValue) => {
console.log(`Example 2: new value is ${newValue}`);
// call onRatingChange function with new rating value
onRatingChange(newValue);
}
};
return (
<div className="starComponent">
<ReactStars {...secondExample} />
</div>
);
}
This is the code for Form component.
const InputData = () => {
const [name, setName] = useState('')
const [rating, setRating] = useState(0)
const onSubmitForm = async(e) => {
e.preventDefault();
try {
const payload = {
name,
rating
}
const response = await fetch("path", {
method:"POST",
headers:{"Content-Type":"application/json"},
body:JSON.stringify(payload)
});
window.location = "/";
} catch (error) {
console.log(error.message);
}
}
return(
<Fragment>
<div className="container">
<h1 className="text-center mt-5">RATE</h1>
<form className="mt-5" onSubmit={onSubmitForm}>
<div className="form-group">
<input
placeholder="Name"
type='text'
className='form-control'
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
<div className="form-group">
<div>
<RatingStar
rating={rating}
onRatingChange={(newRating)=>{
// update rating value here when you get a new value
setRating(newRating);
}}
/>
</div>
</div>
<div className="d-flex justify-content-center">
<button type="submit" className="d-flex btn btn-primary">Submit</button>
</div>
</form>
</div>
</Fragment>
);
}
export default InputData;
You need to keep the state in InputData and pass it into RatingStar with the change handler.
const InputData = () => {
const [rating, setRating] = useState(0);
const handleRatingChange = (newRating) => {
console.log(`setting rating to ${newRating}`);
setRating(newRating);
}
return (
<RatingStar value={rating} onChange={handleRatingChange} />
);
};
Then RatingStar just uses the values from its parent.
const RatingStar = ({ value, onChange }) => {
const otherProps = {};
return (
<ReactStars {...otherProps} value={value} onChange={onChange} />
);
};
Here, RatingStar is a controlled component
I'm trying to grab a todo and add it to an object of todos, can you tell me what's the problem here?
Newbie in React.
import React, { useState } from "react"
function Content() {
const [todo, setTodo] = useState("") // todo: user input
const [todos, setTodos] = useState({}) // todos: object
function handleClick(e) {
e.preventDefault()
setTodos({ ...todo, todos })
}
return (
<>
<h1>Todos</h1>
<form>
<input onChange={(e) => setTodo(e.target.value)} type="text" placeholder="Add Todo Here" />
<button onClick={handleClick}>Add</button>
</form>
{console.log(todos)}
{todos.map((todo) => todo)}
</>
)
}
export default Content
function Content() {
const [todo, setTodo] = useState("") // todo: user input
const [todos, setTodos] = useState([]) // todos: object
function handleClick(e) {
e.preventDefault()
setTodos([ ...todos, todo ])
}
return (
<>
<h1>Todos</h1>
<form>
<input onChange={(e) => setTodo(e.target.value)} type="text" placeholder="Add Todo Here" />
<button onClick={handleClick}>Add</button>
</form>
{console.log(todos)}
{todos.map((todo) => todo)}
</>
)
}
export default function App() {
return (
<div className="App">
<Content />
</div>
);
}
You've mixed todos and todo.. You were trying to spread todo which is a string not an array.
and also, you've not set array right. it should be [] not {}.
:)
here's a code sandbox with a working example:
https://codesandbox.io/s/modest-cerf-soxii
here's the diff between your code and mine:
https://www.diffchecker.com/nBReZt19