checkBox once at the time in React - reactjs

I am trying to select one checkbox at a time in order to setState with a specific value, the problem is that I am not sure if I need to loop over all the checkboxes and un-select the one that I didn't click.
in my case here I am using the value value="Fanny" | value="Abed" in order to identify which checkbox i cliciked
const [check, setcheck] = React.useState(false);
const [checkBoxValue, setCheckBoxValue] = React.useState(null);
const [info, setInfo] = React.useState(null);
React.useEffect(() => {
if (check && checkBoxValue === "Abed") {
setInfo("Abed");
} else if (check && checkBoxValue === "Fanny") {
setInfo("Fanny");
} else {
setInfo(null);
}
}, [check, checkBoxValue]);
return ( <label>
<input
value="Abed"
type="checkbox"
defaultChecked={check}
onChange={(e) => {
setcheck(!check);
setCheckBoxValue(e.target.attributes.value.value);
}}
/>
Abed!
</label>
<label>
<input
value="Fanny"
type="checkbox"
defaultChecked={check}
onChange={(e) => {
setcheck(!check);
setCheckBoxValue(e.target.attributes.value.value);
}}
/>
Fanny!
</label>
</div>
</>
)}
</div>
);

You're making this a lot more complicated than it needs to be. If only one checkbox should be checked, then ultimately that means you only have one value. Meaning you only need to keep track of that value. E.g.:
import { useState } from 'react';
export const Foo = () => {
const [checked, setChecked] = useState(null);
const toggle = evt => setChecked(current => current === evt.target.value ? null : evt.target.value);
return (
<>
<label>
<input
value="Abed"
type="checkbox"
checked={checked === 'Abed'}
onChange={toggle}
/>
Abed!
</label>
<label>
<input
value="Fanny"
type="checkbox"
checked={checked === 'Fanny'}
onChange={toggle}
/>
Fanny!
</label>
</>
);
};

Related

Passing values between components in React

I m beginner to reactJS and I m having so much trouble with self learning.
I want to print the data I get from first page.
I used 2 .js files
This is userpage.js:
import resultPage from "./resultPage";
// JS
//const input = document.getElementById('myText');
//const inputValue = input.value
// React
// value, onChange
const Multi = () => {
const [person, setPerson] = useState({ firstName: "", email: "", age: "" });
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
//e.preventDefault();
if (person.firstName && person.email && person.age) {
const newPerson = { ...person, id: new Date().getTime().toString() };
setPeople([...people, newPerson]);
setPerson({ firstName: "", email: "", age: "" });
resultPage(people, person);
}
};
return (
<>
<article className="form">
<form>
<div className="form-control">
<label htmlFor="firstName">Name : </label>
<input
type="text"
id="firstName"
name="firstName"
value={person.firstName}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="email">Email : </label>
<input
type="email"
id="email"
name="email"
value={person.email}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="age">Age : </label>
<input
type="number"
id="age"
name="age"
value={person.age}
onChange={handleChange}
/>
</div>
<button type="submit" className="btn" onClick={handleSubmit}>
add person
</button>
</form>
</article>
</>
);
};
export default Multi;
This has 2 textboxes and a submit button.
This code is from resultPage.js:
function resultPage(people, person) {
return (
<article>
{people.map((person) => {
const { id, firstName, email, age } = person;
return (
<div key={id} className="item">
<h4>{firstName}</h4>
<p>{email}</p>
<p>{age}</p>
</div>
);
})}
</article>
);
}
export default resultPage;
What am I doing wrong? I m new to reactjs. So kindly spare my obvious mistakes and help me.
From React documentation
HTML form elements work a bit differently from other DOM elements in React, because form elements naturally keep some internal state.
You need to add handleSubmit to your form, and it'll work. As #Halcyon suggested, using a Capital case for a component is good. It's tough to distinguish between HTML elements and components if you use lowercase. Read this for more details.
I am attaching a working sandbox for your code.
You're calling resultPage in handleSubmit. That's not going to work. You want resultPage to be part of the rendering, probably conditionally.
Consider something like:
return <>
{person.firstName !== "" && <resultPage people={people} person={person} />}
{person.firstName === "" && <>
// the form
</>}
</>;
Also since resultPage is a component, it's best to capitalize it.
I think you probably want a 3rd component:
const MyComponent = () => {
const [ people, setPeople ] = React.useState([]);
const [ isEditing, setIsEditing ] = React.useState(false);
return <>
{isEditing && <Multi setPeople={(people) => {
setPeople(people);
setIsEditing(false);
}}
{isEditing === false && <resultPage people={people} />}
</>;
}
Mutli now accepts a prop setPeople that is called in handleSubmit.

Force one selection checkboxe with REACT

how can I force only one check among multiple checkboxes ? For now I can select A, B and C but I only want to select ONE choice no more.
Here is my code :
const TabContent = ({ name, typeText }) => {
const [a, setA] = useState(false)
const [b, setB] = useState(false)
const [c, setC] = useState(false)
function handleChange(e) {
e.preventDefault()
}
return (
<form onSubmit={handleChange} >
{a}
{b}
{b}
<input type="checkbox" onChange={(e) => setA(!a)} /> <label> A </label>
<input type="checkbox" onChange={(e) => setB(!b)} /> <label>B</label>
<input type="checkbox" onChange={(e) => setC(!C)} /> <label>C</label>
</form>
{
(a || b) ?
(<div>
<p className="mt-6 py-1">My choices </p>
<SafeAreaView>
<TextInput
onChangeText={(value) => setText(value)}
value={text}
/>
</SafeAreaView>
</div >
)
: ('')
}
{
c?
(...)
}
</div >
);
};
I think you want to use radio input
Example to illustrate this:
https://codesandbox.io/s/elegant-tess-wu7sl7?file=/src/App.js:0-794
import React, { useState } from "react";
export const TabContent = ({ name, typeText }) => {
const [radio, setRadio] = useState(false);
function handleChange(e) {
e.preventDefault();
}
return (
<form onSubmit={handleChange}>
<input
type="radio"
value="A"
onChange={(e) => setRadio(e.target.value)}
checked={radio === "A"}
/>
<label> A </label>
<input
type="radio"
value="B"
checked={radio === "B"}
onChange={(e) => setRadio(e.target.value)}
/>
<label>B</label>
<input
type="radio"
value="C"
checked={radio === "C"}
onChange={(e) => setRadio(e.target.value)}
/>
<label>C</label>
</form>
);
};
export default TabContent;
This way you only keep track of one state.
You can refactor your state with object state instead of using 3 states
const TabContent = ({ name, typeText }) => {
const [check, setCheck] = useState({selected: "", checked: false})
const handleCheckbox = (type) => {
if(type === check.selected && check.checked) {
setCheck({...check, checked: false})
} else {
setCheck({selected: type, checked: true})
}
}
function handleChange(e) {
e.preventDefault()
}
return (
<form onSubmit={handleChange} >
{check.selected}
<input type="checkbox" onChange={(e) => handleCheckbox("a")} /> <label> A </label>
<input type="checkbox" onChange={(e) => handleCheckbox("b")} /> <label>B</label>
<input type="checkbox" onChange={(e) => handleCheckbox("c")} /> <label>C</label>
</form>
{
(check.selected === ("a" || "b")) ?
(<div>
<p className="mt-6 py-1">My choices </p>
<SafeAreaView>
<TextInput
onChangeText={(value) => setText(value)}
value={text}
/>
</SafeAreaView>
</div >
)
: ('')
}
{
(check.selected === "c") ?
(...)
}
</div >
);
};

How to get checkbox/radio being checked with given dynamic id in React Router

I want to have something like this at 2 hard-code lines with checked that I comment: checked = {searchParams.get('sort') === elementId}. Are there any ways that I can achieve this?
import { useSearchParams } from 'react-router-dom';
const SearchParams = () => {
// searchParams.get('sort') will return "desc"/"asc" if there is "?sort=desc" or "?sort=asc" in the url
const [searchParams, setSearchParams] = useSearchParams();
const handleChange = (event) => {
const { name, id } = event.target;
setSearchParams({ [name]: id });
};
return (
<div>
<input
type="radio"
name="sort"
id="asc"
onChange={handleChange}
checked={searchParams.get('sort') === 'asc'} // hard code at this line...
/>
<label htmlFor="asc">Ascending</label>
<br />
<input
type="radio"
name="sort"
id="desc"
onChange={handleChange}
checked={searchParams.get('sort') === 'desc'} // ... and this line too
/>
<label htmlFor="desc">Descending</label>
</div>
);
};
export default SearchParams;
The problem here is that the element attributes are not accessible until the component has been fully rendered, however if you use a map and iterate over the ids, it will work.
Something like:
const SearchParams = () => {
const [searchParams, setSearchParams] = useSearchParams();
const sortOrder = searchParams.get('sort');
const handleChange = (event) => {
const { name, id } = event.target;
setSearchParams({ [name]: id });
};
return (
<div>
{['ascending', 'descending'].map((val, index) => (
<Fragment key={val}>
<input
type="radio"
name="sort"
id={val}
onChange={handleChange}
checked={sortOrder === val}
/>
<label htmlFor={id}>{id}</label>
{index === 1 ? null : <br />}
</Fragment>
)}
</div>
);
};
export default SearchParams;

Change input values bases on other input onChange

Let's say I want to create a Converter, which means the input value should be changed based on another one.
just to see what I want to do in action https://calolocosta.github.io/romanNumeralsConverter/.
here's what I tried so far but couldn't make it
function LightBulb() {
let [input1, setInput1] = useState("");
let [input2, setInput2] = useState("");
const handleInput1 = (e) => {
setInput2(e.target.value);
};
const handleInput2 = (e) => {
setInput1(e.target.value);
};
return (
<div className="App">
<input
type="text"
value={input2}
onChange={(e) => handleInput1(e)}
placeholder="example 1000"
/>
<input
type="text"
value={input1}
onChange={(e) => handleInput2(e)}
placeholder="example MCMXC"
/>
</div>
);
}
so what I want is to change the input2 value when input1 is typing and vice versa.
Here's the codesandbox that I have been working on: https://codesandbox.io/s/react-hooks-usestate-forked-8o257, any idea would appreciate it.
I guess you will do the rests of the logic for that conversion. But as far as the inputs go and their interaction that needs to change the other one, here is the code changed:
function LightBulb() {
let [input1, setInput1] = useState("");
let [input2, setInput2] = useState("");
const handleInput1 = (e) => {
setInput1(e.target.value);
setInput2("Converted value");
};
const handleInput2 = (e) => {
setInput2(e.target.value);
setInput1("Converted value");
};
console.log(input2);
return (
<div className="App">
<input
type="text"
value={input1}
onChange={(e) => handleInput1(e)}
placeholder="example 1000"
/>
<input
type="text"
value={input2}
onChange={(e) => handleInput2(e)}
placeholder="example MCMXC"
/>
</div>
);
}
You need to set value for corresponding input anyways. But value for the counterpart needs to be set with converted value.
Here is codesandbox also: https://codesandbox.io/s/react-hooks-usestate-forked-667fr?file=/src/index.js:100-777

Clicking on radiobutton returns undefined values

I want to create an app where you can choose quantity fo water that you have drinked. I want to use radiobuttons in form for 3 default values -250ml, 500ml and 1000ml.
I created radiobuttons, but when I click on them, I get undefined value after e.target method.
I tried to bind my functions on checked and onChange but it didn't help.
Main component WaterApp.js:
import WaterButtons from './WaterButtons';
const quantitiesData = [
{
id: 'water_250_ml',
value: 250,
name: 'water_250_ml'
},
{
id: 'water_500_ml',
value: 500,
name: 'water_500_ml'
},
{
id: 'water_1000_ml',
value: 1000,
name: 'water_1000_ml'
}
];
export default class WaterApp extends React.Component {
state = {
waterQuantity: 'water_250_ml'
};
handleCheckedWaterQuantity = (e) => {
this.state.checkedQuantity === e.target.value;
}
handleWaterQuantityChange = (e) => {
const waterQuantity = e.target.value;
this.setState({ waterQuantity });
console.log(waterQuantity);
}
render() {
return (
<div>
<form>
<WaterButtons
quantities={quantitiesData}
handleCheckedWaterQuantity={(e) => this.handleCheckedWaterQuantity(e)}
handleWaterQuantityChange={(e) => this.handleWaterQuantityChange(e)}
/>
</form>
</div>
)
}
}
WaterButtons.js
import WaterButton from './WaterButton';
const WaterButtons = (props) => (
<div>
{
props.quantities.map((quantity) => (
<WaterButton
key={quantity.id}
id={quantity.id}
value={quantity.value}
label={quantity.name}
checked={props.handleCheckedWaterQuantity}
handleWaterQuantityChange={props.handleWaterQuantityChange}
/>
))
}
</div>
);
export default WaterButtons;
WaterButton.js
const WaterButton = (props) => (
<div>
<input
type="radio"
id={props.id}
value={props.value}
name="waterQuantity"
checked={props.checked}
onChange={(e) => {props.handleWaterQuantityChange(props.value)}}
/>
<label htmlFor={props.id}>
{props.label}
</label>
</div>
);
export default WaterButton;
I want to get the value for clicked radiobutton.
[EDIT] Also, I have a problem with checked value for every radiobutton. Function that is now is not working. I thought maybe I should change my code so that in WaterButton.js i define state for buttons. Then it would have to be class not stateless component.
You are calling handleWaterQuantityChange with incorrect argument please see the below code
Your onChange should be onChange={(e) => {props.handleWaterQuantityChange(e)}}
const WaterButton = (props) => (
<div>
<input
type="radio"
id={props.id}
value={props.value}
name="waterQuantity"
checked={props.checked}
onChange={(e) => {props.handleWaterQuantityChange(e)}}
/>
<label htmlFor={props.id}>
{props.label}
</label>
</div>
);
In props.handleWaterQuantityChange you are passing props.value instead of event
<input
type="radio"
id={props.id}
value={props.value}
name="waterQuantity"
checked={props.checked}
onChange={(e) => {props.handleWaterQuantityChange(e)}}
or
<input
type="radio"
id={props.id}
value={props.value}
name="waterQuantity"
checked={props.checked}
onChange={props.handleWaterQuantityChange}

Resources