Creating radio button in React using ref - javascript

Need to create radio buttons for Title (Mr. & Ms.) using react and the ref attribute.
Code for Class(Omitting the useless part):-
getTitle () {
// how could I get the selected title value here
var title = this.refs. ??;
},
render () {
return (
<div className='input-wrap'>
<label className='label'>
Mr.
</label>
<input className='input'
type='radio'
ref= 'title'
name='user_title'
value='Mr.'
selected />
<label className='label'>
Ms.
</label>
<input className=input'
type='radio'
ref= 'title'
name='user_title'
value='Ms.' />
</div>
)
}
Question:- How could I get the selected Title value in getTitle() ?

You can do it without refs.
class Radio extends React.Component{
constructor(){
super();
this.state = {
inputValue : ''
}
}
change(e){
const val = e.target.value;
this.setState({
inputValue : val
})
}
render(){
return <div>
<label>MR<input type="radio" name="name" onChange={this.change.bind(this)} value="MR"/></label>
<label>MS<input type="radio" name="name" onChange={this.change.bind(this)} value="MS"/></label>
<br/>
<h2>Value : {this.state.inputValue}</h2>
</div>
}
}
React.render(<Radio/>, document.getElementById('container'))
Fiddle example is here
I hope it will help you !
Thanks!

Related

boolean state variable change causes parent component to disappear?

What I currently have is a parent component called WhatDo.tsx that has a button which should open a child component called AddToWardrobe.tsx, which is currently simply a form to be filled out. To do this, I've used a { boolean ? ( show AddToWardrobe component):(show button to open component)}. However, when I click on the button, instead of opening the AddToWardrobe component, everything disappears from the page including the WhatDo component.
Here is the function for WhatDo.tsx(note that there are two placeholders for future buttons):
export default function WhatDo() {
const [showATW, setShowATW] = useState(false);
return(
<div className="WhatDo">
<div className="ActionNavText">
What would you like to do?
</div>
<div className="ActionNavButtons">
<button id="actionbutton">placeholder</button>
<div className="Show__ATW">
{showATW?
<div className = "ATW__shown">
<AddToWardrobe onSubmit={postNewItem}/>
<button onClick ={() => setShowATW(false)}>Nvm!</button>
</div>
:
<button id="actionbutton" onClick={() => {setShowATW(true)}}>Add to your Wardrobe</button>
}
</div>
<button id="actionbutton">placeholder</button>
</div>
<div className="SignOutButton">
<button onClick={signOut}>sign out?</button>
</div>
</div>
)
}
and here is the function for AddToWardrobe.tsx:
interface Props {
onSubmit:(Item: Item) => void;
}
export default function AddToWardrobe({onSubmit}: Props) {
const [itemType, setItemType] = useState<string[]>([]);
const [itemPrinted, setItemPrinted] = useState(false);
const [itemColor, setItemColor] = useState<string[]>([]);
const [secondaryColor, setSecondaryColor] = useState<string[]>([]);
//type check boxes
const [accessoryBox, setAccessoryBox] = useState(false);
const [topBox, setTopBox] = useState(false);
const [bottomBox, setBottomBox] = useState(false);
const [shoeBox, setShoeBox] = useState(false);
const handleTypeSet = (e: any) => {
const typeValue = e.target.value;
// check for item type
if(typeValue === "Accessory") {
setItemType(e.target.checked);
}
if(typeValue === "Top") {
setItemType(e.target.checked);
}
if(typeValue === "Bottom") {
setItemType(e.target.checked)
}
if(typeValue === "Shoes") {
setItemType(e.target.checked);
}
}
//check whether or not printed
const handlePrintChange = (e: any) => {
const printValue = e.target.value;
if (printValue === true) {
setItemPrinted(e.target.checked);
} // else false, I guess?
}
function handleSubmit(e:FormEvent) {
e.preventDefault();
const CurrentItem: Item = {
type: itemType,
printed: itemPrinted,
primaryColor: itemColor,
secondaryColor: secondaryColor,
}
onSubmit(CurrentItem);
//probably here the addtowardrobe component will close/return to main screen
// display a message that says if the item was added successfully or not
}
return (
<div className = "AddToWardrobe">
<form onSubmit={handleSubmit}>
<label className = "ATW__question">What would you like to add?</label>
<div className="ATW__input">
<input type="checkbox" value="Accessory" onChange={handleTypeSet} checked={accessoryBox}>Accessory</input>
<input type="checkbox" value="Top" onChange={handleTypeSet} checked={topBox}>Top</input>
<input type="checkbox" value="Bottom" onChange={handleTypeSet} checked={bottomBox}>Bottom</input>
<input type="checkbox" value="Shoes" onChange={handleTypeSet} checked={shoeBox}>Shoes</input>
</div>
<label>Is this item printed, textured, or solid?</label>
<div className="ATW__primarycolor">
<input type="checkbox"></input>
</div>
<input className='submit' type="submit"value ="Submit"/>
</form>
</div>
)
}
It may be worth noting that the form for AddToWardrobe is also not AS complete as it's going to be, but I feel like clicking on the button should be rendering something, or at the very least not making the entire parent component disappear!
<input> cannot have children. But in AddToWardrobe Component , you are enclosing text in <input>
<div className="ATW__input">
<input type="checkbox" value="Accessory" onChange={handleTypeSet} checked={accessoryBox}>Accessory</input>
<input type="checkbox" value="Top" onChange={handleTypeSet} checked={topBox}>Top</input>
<input type="checkbox" value="Bottom" onChange={handleTypeSet} checked={bottomBox}>Bottom</input>
<input type="checkbox" value="Shoes" onChange={handleTypeSet} checked={shoeBox}>Shoes</input>
</div>
instead use it like this
<div className="ATW__input">
<input type="checkbox" value="Accessory" onChange={handleTypeSet} checked={accessoryBox} />
<input type="checkbox" value="Top" onChange={handleTypeSet} checked={topBox} />
<input type="checkbox" value="Bottom" onChange={handleTypeSet} checked={bottomBox}/>
<input type="checkbox" value="Shoes" onChange={handleTypeSet} checked={shoeBox}/>
</div>

React Js : Handle Nested Element In State

I have below Code :-
import React,{useState} from 'react'
const iState ={
Name : '',
Email :'',
Salary :0,
Error:{
EName:'*',
EEmail:'*',
ESalary:'*'
}
}
function ReactForm() {
const [state, setstate] = useState(iState);
function validationHandler(e)
{
console.log(e.target.name);
switch (e.target.name) {
case 'txtName':
if(e.target.value=='')
{
setstate({...state.Error, EName:'Value Cannot be blank'})
}
setstate({...state, Name:e.target.value})
break;
case 'txtEmail':
setstate({...state, Email:e.target.value})
break;
case 'txtSalary':
setstate({...state, Salary:e.target.value})
break;
default:
break;
}
console.log(state);
}
return (
<div>
Name : <input name="txtName" type="text" onChange={(e)=>validationHandler(e)}></input>
<label> {this.state.Error.EName==undefined ? '*':this.state.Error.EName} </label>
<br></br>
Email : <input name="txtEmail" type="text" onChange={(e)=>validationHandler(e)}></input>
<br></br>
Salary : <input name="txtSalary" type="text" onChange={(e)=>validationHandler(e)}></input>
<br></br>
<button onClick={validationHandler}>Validate Us</button>
</div>
)
}
export default ReactForm
I have nested Error element for validation in state -
Error:{
EName:'*',
EEmail:'*',
ESalary:'*'
}
I am trying to bind it to react element as -
Name : <input name="txtName" type="text" onChange={(e)=>validationHandler(e)}></input>
<label> {this.state.Error.EName==undefined ? '*':this.state.Error.EName} </label>
But Getting An Error -
You don't need to use this to access state in functional components. Just do, state.Error.EName. this is only necessary in class components.
You are using functional component and your state is not binded to the class component so you don't need to access it through this.
return (
<div>
Name : <input name="txtName" type="text" onChange={(e)=>validationHandler(e)}></input>
<label> {state.Error.EName==undefined ? '*': state.Error.EName} </label>
<br></br>
Email : <input name="txtEmail" type="text" onChange={(e)=>validationHandler(e)}></input>
<br></br>
Salary : <input name="txtSalary" type="text" onChange={(e)=>validationHandler(e)}></input>
<br></br>
<button onClick={validationHandler}>Validate Us</button>
</div>
)

Changing parent's state from child, but the props of the child don't update

class IQTestItem extends React.Component {
constructor(props) {
super(props)
this.state = {
ItemNumber: 1
}
this.nextItem = this.nextItem.bind(this)
}
nextItem() {
let nextItem = this.state.ItemNumber + 1
this.setState({
itemNumber: nextItem
})
}
render() {
return (
<div>
<img src={'IQTestImages/item ' + this.state.ItemNumber + '/' +this.state.ItemNumber + '.svg'} alt={'item ' + (this.state.ItemNumber)} />
<ItemOptions
itemNumber={this.state.ItemNumber}
nextItem={this.nextItem}
/>
</div>
)
}
}
class ItemOptions extends React.Component {
constructor(props) {
super(props)
}
render() {
let itemNumber = this.props.itemNumber
return(
<div>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.1.svg`} alt={`Option 1`} onClick={this.props.nextItem}/>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.2.svg`} alt={`Option 2`} onClick={this.props.nextItem}/>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.3.svg`} alt={`Option 3`} onClick={this.props.nextItem}/>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.4.svg`} alt={`Option 4`} onClick={this.props.nextItem}/>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.5.svg`} alt={`Option 5`} onClick={this.props.nextItem}/>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.6.svg`} alt={`Option 6`} onClick={this.props.nextItem}/>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.7.svg`} alt={`Option 7`} onClick={this.props.nextItem}/>
<input type="image" src={`IQTestImages/item ${itemNumber}/${itemNumber}.8.svg`} alt={`Option 8`} onClick={this.props.nextItem}/>
</div>
)
}
}
My problem is that if I manually change the ItemNumber in IQTestItem's state, my images all change perfectly fine. When I try to change it with the child Component ItemOptions it changes the state of the parent (IQTestItem) but the child never recieves the updated state of the parent through the props.
I am doing that with onClick={this.props.nextItem}. Does somebody know what I am doing wrong?
Sorry I am fairly new to react.
You have a typo in a nextItem(). Js is case sensitive so instead of itemNumber: nextItem you should do ItemNumber: nextItem
Offtopic - if you are new to react, you shouldn't start with classes. Classes will be soon deprecated. Atm easiest way to learn react are functional components + hooks https://reactjs.org/docs/hooks-intro.html

How to pass form values from child component to parent in react

I am new to react and I am trying to pass the values inside a form to the parent component and then display the values in other child component.
I tried using states and props but it seems like I am missing something. It tells me that you are trying to use props on undefined value. I am not able to figure out where. I tried googling and did some search. nothing works as of now.
Here is my code:
Parent :
constructor(props) {
super(props);
this.state = {
name: "",
age:"",
gender:""
};
}
changeValue(name,age,gender) {
this.setState({
name: name,
age:age,
gender:gender
});
}
render() {
return (
<div>
<FormView changeValue={this.changeValue.bind(this)}/>
<DisplayView name={this.state.name} age= {this.state.age} gender= {this.state.gender}/>
</div>
);
}
Child 1 :
constructor(props) {
super(props);
}
handleChange(e){
this.props.changeValue(e.target.name.value,e.target.age.value,e.target.gender.value);
}
render() {
return <form>
<label>
Name:
<input type="text" name="name" />
</label>
<label>
Age:
<input type="number" name="age" />
</label>
<label>
Gender:
<select name="gender" >
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</label>
<input type="button" value="Submit" onClick = {this.handleChange.bind(this)} />
</form>
}
Child2 :
render(){
return (
<div>
<p>{this.props.name}</p>
<p>{this.props.age}</p>
<p>{this.props.gender}</p>
</div>
)
}
I am expecting to display the form values of child1 in child2.
I am getting an undefined value error.
You component works fine if we define an onSubmit listener and handler for the form. We also need to call event.preventDefault() to stop the page from refreshing, that way the values actually get passed up to parent component when you call this.props.changeValue()
See codesandbox: https://codesandbox.io/s/gallant-ellis-76bdv
import React from "react";
class FormView extends React.Component {
constructor(props) {
super(props);
}
handleChange(e){
e.preventDefault()
this.props.changeValue(
e.target.name.value,
e.target.age.value,
e.target.gender.value
);
};
render() {
return (
<form onSubmit={this.handleChange.bind(this)}>
<label>
Name:
<input type="text" name="name" />
</label>
<label>
Age:
<input type="number" name="age" />
</label>
<label>
Gender:
<select name="gender">
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default FormView;
To get an element in React you can use refs on each input or one on the form https://reactjs.org/docs/refs-and-the-dom.html
constructor(props) {
super(props);
}
handleChange(e){
console.log(this.name.value, this.age.value, this.gender.value);
this.props.changeValue(this.name.value, this.age.value, this.gender.value);
}
setName = (name) => {
this.name = name;
}
setAge = (age) => {
this.age = age;
}
setGender = (gender) => {
this.gender = gender;
}
render() {
return <form>
<label>
Name:
<input type="text" ref={this.setName} name="name" />
</label>
<label>
Age:
<input type="number" ref={this.setAge} name="age" />
</label>
<label>
Gender:
<select ref={this.setGender} name="gender" >
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</label>
<input type="button" value="Submit" onClick = {this.handleChange.bind(this)} />

keeping data in 'this' VS 'state'

I wonder is it okay to keep some UI state as instance variables(this) rather than in react state object. For example making controlled inputs sometimes becomes tedious, wouldn't it be better to keep it like:
import React from 'react';
export default class extends React.Component {
selectedCheckboxes = new Set();
searchInput = '';
radioButton = undefined;
onCheckboxChange = ({target: {value}}) => {
if (this.selectedCheckboxes.has(value)) {
this.selectedCheckboxes.delete(value);
} else {
this.selectedCheckboxes.add(value);
}
};
submit = e => {
e.preventDefault();
const searchInput = this.searchInput;
const checkboxes = [...this.selectedCheckboxes];
const radioButton = this.radioButton;
console.log(searchInput, checkboxes, radioButton);
};
render() {
return (
<form className="Example" onSubmit={this.submit}>
<div className="checkboxes">
<input type="checkbox" value="a" onChange={this.onCheckboxChange}/>
<input type="checkbox" value="b" onChange={this.onCheckboxChange}/>
<input type="checkbox" value="c" onChange={this.onCheckboxChange}/>
</div>
<div className="search">
<input type="text" onChange={e => this.searchInput = e.target.value}/>
</div>
<div className="radio-buttons">
<input type="radio"
name="radio"
value="1"
onChange={e => this.radioButton = e.target.value}/>
<input type="radio"
name="radio"
value="2"
onChange={e => this.radioButton = e.target.value}/>
<input type="radio"
name="radio"
value="3"
onChange={e => this.radioButton = e.target.value}/>
</div>
<button type="submit">submit</button>
</form>
)
}
}
I know downside of this approach is that component is not notified when value of this-variables has changed so component will not update. But on the other side sometimes it is not neccessary (like in my example) and it can boost performance as it dont triger re-render, and avoids reconcilation.
Reference

Categories

Resources