Push Multiple checkbox data in array in ReactJs? - javascript

I need to push the data in array form, from checkbox value.
Code
import React,{ useState,useEffect } from "react";
export default function App() {
const [person, setPerson] = useState([]);
const CheckHandler = () => {
// setPerson(() => { ...person, })
}
useEffect(() => {
//Print data each time the checkbox is "checked" or "unchecked"
console.log(person);
}, [person]);
return (
<>
<input type="checkbox" id="jane" name="jane" value="jane" onClick={() => CheckHandler()} />
<label htmlFor="jane">jane</label><br/>
<input type="checkbox" id="Mike" name="Mike" value="Mike" onClick={() => CheckHandler()} />
<label htmlFor="Mike">Mike</label><br/>
<input type="checkbox" id="board" name="board" value="board" onClick={() => CheckHandler()} />
<label htmlFor="board">board</label><br/>
</>
);
}
What should I do to get my data in array in my console?
sandbox : https://codesandbox.io/s/adoring-rgb-27wkt

Do you want like this and I also added add and removed filter
const CheckHandler = (e) => {
const value = e.target.value;
setPerson((prev) =>
person.includes(value)
? prev.filter((cur) => cur !== value)
: [...prev, e.target.value]
);
};
FULL CODE
import React, { Fragment, useState, useEffect } from "react";
export default function App() {
const [person, setPerson] = useState([]);
const CheckHandler = (e) => {
setPerson((prev) => [...prev, e.target.value]);
};
useEffect(() => {
//Print data each time the checkbox is "checked" or "unchecked"
console.log(person);
}, [person]);
return (
<Fragment>
<input
type="checkbox"
id="jane"
name="jane"
value="jane"
onClick={CheckHandler}
/>
<label htmlFor="jane">jane</label>
<br />
<input
type="checkbox"
id="Mike"
name="Mike"
value="Mike"
onClick={CheckHandler}
/>
<label htmlFor="Mike">Mike</label>
<br />
<input
type="checkbox"
id="board"
name="board"
value="board"
onClick={CheckHandler}
/>
<label htmlFor="board">board</label>
<br />
</Fragment>
);
}
Codesandbox: https://codesandbox.io/s/twilight-hill-lh9bv?file=/src/App.js:0-986

Related

How to pass multiple onChange form data from child to parent element in react

I am trying to print real-time user input from input tags by the user. I am even getting multiple user inputs from the child element to the parent element as a form of an object using useState. But whenever the user tries to fill the second input field, then the first input is re-render and it's replaced by the primary state which is an empty string.
code:-
Child Element
import React, { useState } from "react";
const Child = (props) => {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = {
name: "",
age: ""
};
const nameChangeHandler = (e) => {
setName(e.target.value);
userData.name = e.target.value;
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
userData.age = e.target.value;
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
Parent Element
import React, { useState } from "react";
import Child from "./components/Child";
function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = (data) => {
setName(data.name);
setAge(data.age);
};
return (
<React.Fragment>
<Child getData={userData} />
<h1>Your name is:{name}</h1>
<h1>Your age is:{age}</h1>
</React.Fragment>
);
}
export default App;
code sandbox Link- https://codesandbox.io/s/from-traversing-child-to-parent-to-another-child-ynwyqd?file=/src/App.js:0-441
How I can get both data being reflected by using onChange from child to parent element?
I suggest you accumulate the user data in one state.
Like this.
const [user, setUser] = useState({
name: "",
age: null
});
And put the state on the parent and pass as props, also just have one handleChange function to update both the name and age by the input id
Child.js
import React, { useState } from "react";
const Child = ({ user, setUser }) => {
const handleChange = (e) => {
setUser((prev) => ({
...prev,
[e.target.id]: e.target.value
}));
};
const formOnChageHandler = (e) => {
e.preventDefault();
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={user.name}
onChange={handleChange}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={user.age}
onChange={handleChange}
/>
</form>
</React.Fragment>
);
};
export default Child;
App.js
import React, { useState } from "react";
import Child from "./components/Child";
function App() {
const [user, setUser] = useState({
name: "",
age: null
});
return (
<React.Fragment>
<Child user={user} setUser={setUser} />
<h1>Your name is:{user.name}</h1>
<h1>Your age is:{user.age}</h1>
</React.Fragment>
);
}
export default App;
CODESANDBOX
Try using the child component as below,
import React, { useState } from "react";
const Child = (props) => {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = {
name: name, // the value "name" comes for the local state will be listen to the onChange event every time
age: age // same applies here as well
};
const nameChangeHandler = (e) => {
setName(e.target.value);
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
just use simple one state to manage data. just take a look below example component created from your child component.
we simply use single object state.
use name prop as key to store value in state.
import React, { useState } from "react";
const Child = (props) => {
const [formData, setFormData] = useState({});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setFormData({
...formData,
[e.target.name]: e.target.value,
});
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={handleChange}
name="name"
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={handleChange}
name="age"
/>
</form>
</React.Fragment>
);
};
export default Child;
<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>
it happens because you dont watch to the state, try this:
Child.js
import React, { useState } from "react";
const Child = (props) => {
const [name, setName] = useState("");
const [age, setAge] = useState("");
let userData = {
name,
age
};
const nameChangeHandler = (e) => {
setName(e.target.value);
userData.name = e.target.value;
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
userData.age = e.target.value;
};
const formOnChageHandler = (e) => {
e.preventDefault();
props.getData(userData);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onChange={formOnChageHandler} onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
Try this, i check in codesandbox and it works:
In App.js:
import React, { useState } from "react";
import Child from "./components/Child";
function App() {
const [name, setName] = useState("");
const [age, setAge] = useState("");
return (
<React.Fragment>
<Child name={name} age={age} setName={setName} setAge={setAge} />
<h1>Your name is:{name}</h1>
<h1>Your age is:{age}</h1>
</React.Fragment>
);
}
export default App;
In Child.js:
import React, { useState } from "react";
const Child = ({ name, age, setName, setAge }) => {
const nameChangeHandler = (e) => {
setName(e.target.value);
};
const ageChangeHandler = (e) => {
setAge(e.target.value);
};
const fromOnSubmitHandler = (e) => {
e.preventDefault();
};
return (
<React.Fragment>
<form onSubmit={fromOnSubmitHandler}>
<label htmlFor="name">Name:</label>
<input
id="name"
placeholder="Enter Name"
value={name}
onChange={nameChangeHandler}
/>
<br />
<label htmlFor="age">Age:</label>
<input
id="age"
placeholder="Enter Age"
value={age}
onChange={ageChangeHandler}
/>
</form>
</React.Fragment>
);
};
export default Child;
If you want to improve your code, you can research and use state management like: redux, zustand, react context,...
Hope it useful for you.

React: Fetch Data onSubmit, not on onChange

I got this code working pretty much how I want it. However, it's fetching & display data after each keystroke. I only want it to fetch once, when I hit submit.
Also, if there's anything i'm doing that's not "best practice" please let me know so I don't make silly mistakes in the future.
import React, { useEffect, useState } from "react";
export default function App() {
const [data, setData] = useState(null);
const [query, setQuery] = useState("");
useEffect(() => {
if (!query) return;
async function fetchData() {
const response = await fetch(
`https://www.omdbapi.com/?apikey=2e8b5857&s=${query}`
);
const data = await response.json();
const results = data.Search;
setData(results);
}
fetchData();
}, [query]);
const handleSubmit = (e) => {
e.preventDefault();
setQuery(query);
};
return (
<div
style={{
margin: 20,
}}
>
<form onSubmit={handleSubmit}>
<br />
<label>
Input Movie:{" "}
<input
type="text"
placeholder="ex. Harry Potter"
value={query}
onChange={(e) => {
setQuery(e.target.value);
}}
/>
</label>
<input type="submit" value="Submit" onClick={() => setQuery} />
</form>
{data &&
data.map((movie) => (
<div key={movie.imdbID}>
<h1>{movie.Title}</h1>
<h4>
{movie.Year} | {movie.imdbID}
</h4>
<img alt={movie.imdbID} src={`${movie.Poster}`} />
</div>
))}
</div>
);
}
Since you only want it after submit, you can skip the useEffect with [query] and just copy the same logic inside your handleSubmit like so :-
import React, { useEffect, useState } from "react";
export default function App() {
const [data, setData] = useState(null);
const [query, setQuery] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!query) return;
async function fetchData() {
const response = await fetch(
`https://www.omdbapi.com/?apikey=2e8b5857&s=${query}`
);
const data = await response.json();
const results = data.Search;
setData(results);
}
fetchData();
};
return (
<div
style={{
margin: 20,
}}
>
<form onSubmit={handleSubmit}>
<br />
<label>
Input Movie:{" "}
<input
type="text"
placeholder="ex. Harry Potter"
value={query}
onChange={(e) => {
setQuery(e.target.value);
}}
/>
</label>
<input type="submit" value="Submit"/>
</form>
{data &&
data.map((movie) => (
<div key={movie.imdbID}>
<h1>{movie.Title}</h1>
<h4>
{movie.Year} | {movie.imdbID}
</h4>
<img alt={movie.imdbID} src={`${movie.Poster}`} />
</div>
))}
</div>
);
}
Here's the codesandbox :-
Pass the code that is inside the useEffect, that is, the fetch function, inside the submit function. leaving useEffect unused

Returning two same properties instead of one in ReactJS

I have a problem that my React app saving 2 same properties on one query.
After I enter the data in two input field and click Set button I receive double of same data.
CODE HERE
import React, { useState } from "react";
export default function App() {
const [queries, setQueries] = useState([]);
const [symbol, setSymbol] = useState("");
const [price, setPrice] = useState("");
const onChangeSymbol = e => {
setSymbol(e.target.value);
};
const onChangePrice = e => {
setPrice(e.target.value);
};
const onClick = () => {
if (symbol !== "" && price !== "") {
setQueries((queries) => {
queries.push(`${symbol}${price}`);
return queries;
});
setSymbol("");
setPrice("");
}
}
return (
<div className="App">
<h6>Price Alert History</h6>
<ul>
{queries.map(query => <li>{query}</li>)}
</ul>
<input
type="text"
placeholder="Symbol"
value={symbol}
onChange={onChangeSymbol}
/>
<input
type="number"
placeholder="Price"
value={price}
onChange={onChangePrice}
/>
<button type="submit" onClick={onClick}>Set</button>
</div>
);
}
GOAL: I just want to receive one property instead of double of it.
You need just to fix your function and it will work properly
const onClick = () => {
if (symbol !== "" && price !== "") {
setQueries((queries) => {
return [ ...queries, `${symbol}${price}`] // fix here
});
setSymbol("");
setPrice("");
}
}
import React, { useState } from "react";
export default function App() {
const [queries, setQueries] = useState([]);
const [symbol, setSymbol] = useState("");
const [price, setPrice] = useState("");
const onChangeSymbol = e => {
setSymbol(e.target.value);
};
const onChangePrice = e => {
setPrice(e.target.value);
};
const onClick = () => {
if (symbol !== "" && price !== "") {
setQueries((queries) => {
return [ ...queries, `${symbol}${price}`]
});
setSymbol("");
setPrice("");
}
}
return (
<div className="App">
<h6>Price Alert History</h6>
<ul>
{queries.map(query => <li>{query}</li>)}
</ul>
<input
type="text"
placeholder="Symbol"
value={symbol}
onChange={onChangeSymbol}
/>
<input
type="number"
placeholder="Price"
value={price}
onChange={onChangePrice}
/>
<button type="submit" onClick={onClick}>Set</button>
</div>
);
}
I would have refactored it so that the price and symbol would be an object with keys
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [queries, setQueries] = useState([]);
const [symbol, setSymbol] = useState("");
const [price, setPrice] = useState("");
const onClick = () => {
if (symbol !== "" && price !== "") {
const product = {
symbol: symbol,
price: price
};
setQueries([...queries, product]);
setSymbol("");
setPrice("");
}
};
return (
<div className="App">
<h6>Price Alert History</h6>
<ul>
{queries.map(query => (
<li>
{query.symbol} {query.price}
</li>
))}
</ul>
<input
type="text"
placeholder="Symbol"
value={symbol}
onChange={e => setSymbol(e.target.value)}
/>
<input
type="number"
placeholder="Price"
value={price}
onChange={e => setPrice(e.target.value)}
/>
<button type="submit" onClick={onClick}>
Set
</button>
</div>
);
}

React loop with useState

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

Bind child component click handler to parent state

None of the other SO answers have helped, so I think I'm missing something conceptually.
I have a Parent (Wrapper) component, and a Child (Input) component. The Parent passes a function down to the child:
const Wrapper = () => {
const [dictionary, setDictionary] = useState([{ word: "init", definition: "def init" }]);
const handleWordChange = (e, value) => {
e.preventDefault();
/// IS NEVER TRIGGERED
};
return (
<Input setDictionary={{ setDictionary }} onChange={handleWordChange} />
)
}
The child component handles its own state, but is supposed to update the Parent props by calling the setDictionary function:
const Input = props => {
const [definition, setDefinition] = useState("");
const [word, setWord] = useState("");
const handleSubmit = e => {
const { setDictionary } = props.setDictionary;
e.preventDefault();
setDictionary([{ word, definition }]);
}
return (
<form onSubmit={handleSubmit}>
<input
name='word'
onChange={e => setWord(e.target.value)}
onFocus={() => setWord("")}
placeholder='Word'
type='text'
value={word}
/>
<input
name='definition'
onChange={e => setDefinition(e.target.value)}
onFocus={() => setDefinition("")}
placeholder='Definition'
type='text'
value={definition}
/>
<input type='submit' value='Submit' />
</form>
)
}
Other answers I have seen suggest to pass a callback to the Child (setDictionary), but the onChange handler is never called on change. I've also tried to use onSubmit instead.
How do I successfully update dictionary?
I know the above creates a dependency of the Child to the Parent, is there a better programmatic way to achieve this, considering that I eventually need to pass down dictionary to a 2nd child?
You cannot assign child's onChange() event handler this way.
Instead, you refer to child event handlers as props and bind parent callbacks to those props.
The concept is known as lifting state up.
Complete live-demo of your use case you may find below:
const { render } = ReactDOM,
{ useState } = React
const Input = ({onInput}) => {
const [word, setWord] = useState(''),
[definition, setDefinition] = useState('')
return (
<form onSubmit={e => (e.preventDefault(), onInput(word, definition))}>
<label>
Word:
<input onChange={({target:{value}}) => setWord(value)} />
</label>
<label>
Definition:
<input onChange={({target:{value}}) => setDefinition(value)} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
const List = ({list}) => (
<ul>
{
list.map(({word,definition},key) => <li {...{key}}><strong>{word}</strong> - {definition}</li>)
}
</ul>
)
const Parent = () => {
const [dictionary, setDictionary] = useState([]),
onDicionaryItemSubmit = (word,definition) => setDictionary([...dictionary, {word,definition}])
return (
<div>
<Input onInput={onDicionaryItemSubmit} />
<List list={dictionary} />
</div>
)
}
render (
<Parent />,
document.getElementById('root')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
//there is not props.onChange here in this component
const Input = props => {
const [definition, setDefinition] = useState("");
const [word, setWord] = useState("");
const handleSubmit = e => {
const { setDictionary } = props.setDictionary;
e.preventDefault();
setDictionary([{ word, definition }]);
//like here
props.onChange(any arguments);
}
return (
<form onSubmit={handleSubmit}>
<input
name='word'
onChange={e => {
setWord(e.target.value)
props.onChange();
}}
onFocus={() => setWord("")}
placeholder='Word'
type='text'
value={word}
/>
<input
name='definition'
onChange={e => {
setDefinition(e.target.value)
props.onChange();
}}
onFocus={() => setDefinition("")}
placeholder='Definition'
type='text'
value={definition}
/>
<input type='submit' value='Submit' />
</form>
)
}
Use parent onChange() method in your Input Component than it will be triggered if you didn't call that method than how it will triggered i hope this will help you.
You're not even triggering onChange passed to component
<Input setDictionary={{ setDictionary }} onChange={handleWordChange} />
you have to do exactly as you named the prop like props.onChange
//there is no props.onChange here in this component
const Input = props => {
const [definition, setDefinition] = useState("");
const [word, setWord] = useState("");
const handleSubmit = e => {
const { setDictionary } = props.setDictionary;
e.preventDefault();
setDictionary([{ word, definition }]);
//like here
props.onChange(any arguments);
}
return (
<form onSubmit={handleSubmit}>
<input
name='word'
onChange={e => setWord(e.target.value)}
onFocus={() => setWord("")}
placeholder='Word'
type='text'
value={word}
/>
<input
name='definition'
onChange={e => setDefinition(e.target.value)}
onFocus={() => setDefinition("")}
placeholder='Definition'
type='text'
value={definition}
/>
<input type='submit' value='Submit' />
</form>
)
}
If i rename
<Input setDictionary={{ setDictionary }} onInputChanged={handleWordChange} />
i'd call it like
const handleSubmit = e => {
const { setDictionary } = props.setDictionary;
e.preventDefault();
setDictionary([{ word, definition }]);
//like here
props.onInputChanged(any arguments);
}
Error:- not calling onChange function in <Input/> and setting state of dictionary in <Wrapper />. This is the working solution of your query.
const {useState} = React;
const Wrapper = () => {
const [dictionary, setDictionary] = useState([
{ word: "computer", definition: "an electronic device for storing and processing data" }
]);
const handleWordChange = (e, value) => {
e.preventDefault();
let updateDictionary = [...dictionary];
updateDictionary.push(value);
setDictionary(updateDictionary);
// console.log(updateDictionary);
/// IS NEVER TRIGGERED
};
return (
<React.Fragment>
<Input onChange={handleWordChange} />
{dictionary.length > 0 ? (
<table>
<tr>
<th>WORD</th>
<th>DEFINITION</th>
</tr>
{dictionary.map(datum => (
<tr>
<td>{datum.word}</td>
<td>{datum.definition}</td>
</tr>
))}
</table>
) : null}
</React.Fragment>
);
};
const Input = props => {
const [definition, setDefinition] = useState("");
const [word, setWord] = useState("");
const handleSubmit = e => {
e.preventDefault();
props.onChange(e, { word, definition });
};
return (
<form onSubmit={handleSubmit}>
<input
name="word"
onChange={e => setWord(e.target.value)}
onFocus={() => setWord("")}
placeholder="Word"
type="text"
value={word}
/>
<input
name="definition"
onChange={e => setDefinition(e.target.value)}
onFocus={() => setDefinition("")}
placeholder="Definition"
type="text"
value={definition}
/>
<input type="submit" value="Submit" />
</form>
);
};
ReactDOM.render(<Wrapper />, document.getElementById('root'));
table,
th,
td {
border: 1px solid black;
}
table {
margin-top: 20px;
}
<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>
<div id="root"></div>

Categories

Resources