Giving Options to the User and then Displaying the chosen option - reactjs

So, i have just started working on React and i have a doubt. So, i want to create two different forms and then allow user to fill one form by selecting that form. So, i have created both the forms now how do i create a page where i give options to the user to choose one and after the user chooses first option, then the first option form displays. How do i do that? I have created both the forms, now i just need help with how to link those two forms to the pages where i am giving option to the user.
So, do i need to create a third component like the other two containers. Those forms are basically are two different containers. So, how do i work on the third container?
Thanks

Firs you need two radio inputs that user will select them and a variable that will hold the selected value and will change on onChange:
const [selected, setSelected] = useState("first");
function onChange({ target }) {
setSelected(target.value);
}
return {
<label>
<input value="first" onChange={onChange} type="radio" name="forms" checked={selected === "first"} />
First Form
</label>
<label>
<input value="second" onChange={onChange} type="radio" name="forms" checked={selected === "second"} />
Second Form
</label>
}
Then you need to show forms based on what the selected value is:
{selected === "first" && <FirstForm />}
{selected === "second" && <SecondForm />}
So when selected is 'first' it will show FirstForm component otherwise when its 'second' it will show 'SecondForm'.
So the final MainComponent will be like this:
import React, { useState } from 'react';
import FirstForm from './first-form.js';
imprt SecondForm from './second-form.js';
function MainComponent() {
const [selected, setSelected] = useState("first");
function onChange({ target }) {
setSelected(target.value);
}
return (
<div className="App">
<h1>Select Form</h1>
<label>
<input value="first" onChange={onChange} type="radio" name="forms" checked={selected === "first"} />
First Form
</label>
<label>
<input value="second" onChange={onChange} type="radio" name="forms" checked={selected === "second"} />
Second Form
</label>
{selected === "first" && <FirstForm />}
{selected === "second" && <SecondForm />}
</div>
);
}

Related

How to set radio button 'checked' based on value from database? - React

I have a radio button group in a component. I want to set which radio is selected based on it's value taken from the database in an Update/Edit scenario.
export default function updateRadioSelection(){
const [radioValue, setRadiovalue] = useState("");
useState(()=>{
setRadiovalue("pick"); // <-- Assume this value is taken from database, value may be either "delivery" or "pick"
}, [])
const changeSelection = (e)=>{
setRadiovalue(e.target.value);
}
return(
<div>
<input type="radio" id="delivery" name="orderType" value="delivery" required onChange={changeSelection} />
<label htmlFor="delivery">Delivery</label>
<input type="radio" id="pick" name="orderType" value="pick" onChange={changeSelection} />
<label htmlFor="pick">Pick Up</label>
</div>
)
}
To make a checkbox or radio checked you must use the checked prop for the input element, it receives a boolean value. And you can do something like this
export default function updateRadioSelection(){
const [radioValue, setRadiovalue] = useState("");
// useState will not execute any kind of callback function, for this case you need to use useEffect
useEffect(() => {
const dbResult = getRadioFromDb();
setRadiovalue(dbResult);
}, [])
const changeSelection = (e)=>{
setRadiovalue(e.target.value);
}
return(
<div>
<input type="radio" id="delivery" name="orderType" value="delivery" required onChange={changeSelection} checked={radioValue === 'delivery'} />
<label htmlFor="delivery">Delivery</label>
<input type="radio" id="pick" name="orderType" value="pick" onChange={changeSelection} checked={radioValue === 'pick'} />
<label htmlFor="pick">Pick Up</label>
</div>
)
}
You can read more about radio input in its documentation
Just a few minutes after posting this question I found the answer I was searching for. Turns out it's pretty easy.
Just add checked={radioValue === "pick"} for the Pick Up radio button & the same for other radio button by replacing "pick" with "delivery"
reference - react.tips/radio-buttons-in-reactjs

React can not use conditionally rendering on a component due to variables being nested inside of my form

I want to conditionally render a component in this case if the user submits a wrong answer, the input is stored as a javascript object called data and gets converted to a string called userInput.
After looking around, I got recommended to create a conditional rendering with a state outside of the form, but the problem I ran across is that since the variables are initialized inside of my form, i can't use ternaries to conditionally render my component in so I'm a bit stuck in what to do.
<main class="gameSection">
<h1>Welcome to League of Wordle!</h1>
<form
onSubmit={handleSubmit((data) => {
let userInput = data.guess;
console.log(userInput);
const championList = Object.keys(champions);
if (userInput.valueOf().toUpperCase() !== correctChampion.valueOf().toUpperCase()) {
<Wrong text="Class" alt="wrong img" img={wrong} />
}
})
}
>
<input
{...register("guess")} class="guess_input" placeholder="Enter Champion Name Here" type="text" />
<input class="guess_input" type="submit" />
</form>
</main>
I suggest you create a state to track if any answers submitted is wrong.
const [isWrong, setIsWrong] = useState(false)
Now, after each submit, update isWrong's value based on input.
onSubmit={handleSubmit((data) => {
let userInput = data.guess;
console.log(userInput);
const championList = Object.keys(champions);
if (userInput.valueOf().toUpperCase() !== correctChampion.valueOf().toUpperCase()) {
setIsWrong(true)
}
else {setIsWrong(false) } // logic in case of correct answer
})
}
Finally, you can implement conditional rendering:
<main class="gameSection">
<h1>Welcome to League of Wordle!</h1>
<form
...
>
<input
{...register("guess")} class="guess_input" placeholder="Enter Champion Name Here" type="text" />
<input class="guess_input" type="submit" />
{isWrong && <Wrong text="Class" alt="wrong img" img={wrong} /> }
</form>
</main>

useSelector is unable to fetch latest value of state after re-render and return null

I am building a user page, in which i am getting user info from state itself using useState hook of redux.
import React, { useState, useEffect } from "react";
import profileImage from "../../resources/images/defaultProfile.png";
import { useSelector, useDispatch } from "react-redux";
import { userActions } from "../../state/actions";
const User = () => {
const [isEditable, setIsEditable] = useState(false);
const onChange = (e) => {
setUser({
...user,
[e.target.name]: [e.target.value],
});
};
const onSubmit = () => {
if (!isEditable) {
setIsEditable(!isEditable);
} else {
//TODO update user data here
}
};
const [user, setUser] = useState(useSelector((state) => state.user.user));
return (
user !== null && (
<div className="container-fluid">
<div className="row">
<div className="col-md-9 border border-primary">user preference</div>
<div className="col-md-3 border border-primary">
<div className="row-cols-md-3 text-center">
<img
src={profileImage}
alt="Profile image"
style={{ width: "60%", height: "70%" }}
className="border rounded-circle"
/>
<form onSubmit={onSubmit} style={{ width: "100%" }}>
<div className="mb-3">
<label htmlFor="userName" className="form-label">
User Name
</label>
<input
type="text"
name="name"
id="userName"
value={user.name}
onChange={onChange}
disabled={!isEditable ? "disabled" : ""}
className="form-control"
/>
</div>
<div className="mb-3">
<label htmlFor="userEmail" className="form-label">
User Email
</label>
<input
type="email"
name="email"
disabled={!isEditable ? "disabled" : ""}
id="userEmail"
value={user.email}
onChange={onChange}
className="form-control"
/>
</div>
<div className="mb-3">
<label htmlFor="userPhone" className="form-label">
User Phone Number
</label>
<input
type="text"
disabled={!isEditable ? "disabled" : ""}
name="phoneno"
id="userPhone"
value={user.phoneno}
onChange={onChange}
className="form-control"
/>
</div>
<button type="submit">{isEditable ? "Update" : "Edit"}</button>
</form>
</div>
</div>
</div>
</div>
)
);
};
export default User;
The data is loading fine for the first time. As shown initially all my input field are disabled but once i click on edit, it changes state isEditable and enables every field and change the submit button to "update" .It's re-render the page once the state isEditable is changed. I am loading navbar by default for every page and navBar has code which reloads the value of user state in case of refresh and once the page re-renders it reloads the user global state but somehow useSelector is unable to get latest value and just returns the null value.
Observation -
once the complete re-renders happen useSelector is unable to fetch latest user data although the state has the latest value.
Can somebody please suggest what approach should i choose to overcome the following scenerio.
Never do
useState(useSelector(...));
It does not do what you expect.
useState is initialized once with the argument you put into it - so at first render, it will "capture" the value the selector returns at that point in time. But it will never update the state once the return value from useSelector changes. The local state is initialized after all.
Well i was surfing internet for the following issue and i found this.
https://dmitripavlutin.com/react-forms-tutorial/
" By default, when clicking the form’s Submit button, the browser performs a full-page POST request to the URL specified in the action attribute of the . But having the form controlled by React, you can prevent browser’s default behavior by attaching an event handler to onSubmit event and calling event.preventDefault(). "
And based on this i bring my button out of the form, since now no complete post request would be called and hence it started working.
Frankly i am still not sure, earlier why it was working fine after second click.

Radio ref on react

I have radio input use want to use ref to show the result on console.
I always get second value even when I have choose the first one.
This is the constructor
this.inputKelamin = React.createRef();
and rendered like this
<div>
Jenis Kelamin :
<input name="kelamin" type="radio" value="laki - laki" ref={this.inputKelamin}/>
Laki - laki
<input name="kelamin" type="radio" value="perempuan" ref={this.inputKelamin}/>
Perempuan
</div>
onSubmit, I put it like this via console :
alamat : ${this.inputAlamat.current.value}
the result is always "perempuan"
This is not for production, just a learning purpose, thank you
You're using same ref for both the element, second ref={this.inputKelamin} overrides the first one and it always points to the second radio button.
From official docs
Refs provide a way to access DOM nodes or React elements created in the render method.
You should create 2 different refs for both inputs.
And you're checking the wrong property here
this.inputAlamat.current.value
value will always be the attribute value you gave value="perempuan".
In case of radio you should look at the checked property, which tells you whether it was selected
this.inputKelamin.current.checked
Also, you might want to look at controlled and un-conntrolled components
In order to get just one data from multiple radio you cam simply do this :
Example with typescript :
import React, { useRef } from "react";
function Form() {
const inputKelamin = useRef() as React.MutableRefObject<HTMLInputElement>;
const inputLaki = useRef() as React.MutableRefObject<HTMLInputElement>;
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const selectedRadio = inputKelamin.current.checked ? inputKelamin.current.value : inputLaki.current.value
console.log(selectedRadio);
}
return (
<form className="form" onSubmit={handleSubmit}>
Jenis Kelamin :
Laki - laki <input type="radio" value="laki - laki" ref={inputKelamin} /> <br />
Perempuan <input type="radio" value="perempuan" ref={inputLaki} /> <br />
<button type="submit">Submit</button>
</form>
);
}
export default Form;

Send an array to a Redux Form to generate options in a select drop down

Working on the setting security questions part of the authentication. The server responds with a list of the 20 or so questions in the form of an array. I can get the form and select box to render, but only one option at a time by specifying the index.
If I try to send the entire array I get an undefined error. Tried to do a for loop in the ` to iterate through each index, which generated an error.
I'm trying to figure out how to pass the entire array so it makes an option for each entry in the array.
This is what I have so far:
// ./set_security_questions.js
// This renders errors regarding the form inputs
renderField(field) {
const {
label,
placeholder,
type,
name,
questions,
meta: {
touched,
error
}
} = field;
return (
<div className='form-group'>
<label>{label}</label>
<select className='form-control' name={name}>
<option value={questions}>{questions}
</option>}
</select>
<input
className='form-control'
type={type}
placeholder={placeholder}
{...field.input}
/>
<div className='text-danger'>
{touched ? error : ""}
</div>
</div>
);
}
// The main body to be rendered
render() {
if (this.props.permitRender) {
const { handleSubmit } = this.props;
return (
<div>
<h3>Set Security Questions</h3>
<p>Please select two security questions that will be easy for you to remember.</p>
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
{this.renderAlert()}
<Field
questions={this.props.questions.data.security_question}
label='Question 1'
placeholder='Answer 1'
name='a1'
type='text'
component={this.renderField}
/>
<Field
label='Question 2'
placeholder='Answer 2'
name='a2'
type='text'
component={this.renderField}
/>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
);
} else if (!this.props.permitRender) {
return (
<div> { this.renderAlert() } </div>
);
}
}
In addition, my JSON that comes back from the server looks pretty strange, so I will need to iron that out, but still wondering how to pass an array into the Form. this.props.questions.data:
data:
id: 123
key: "key_request"
security_q1: null
security_q2: null
security_question: Array(29)
0: {security_question: "In what city or town did you meet your spouse / partner?"}
1: {security_question: "In what city or town did your mother and father meet?"}
2: {security_question: "In what town or city was your first full time job?"}
3: {security_question: "What is the first name of your spouse's father?"}
......
Here is an example I'm currently using to populate a set of checkboxes. There isn't any special logic going on in the checkbox component, I just am using custom html for styling purposes.
Here is my data, a simple array:
const env = {
FONT_FORMATS: ['OTF', 'TTF', 'WOFF', 'WOFF2']
}
Here is the code in the render() function for my component. I'm storing each item in the Redux form under the object key -> fileTypes.
<ul className='tags'>
{envConfig.FONT_FORMATS.map((tag: string) => (
<Field
key={tag}
value={tag}
name={`fileTypes.[${tag}]`}
id={tag.toLowerCase().replace(' ', '_')}
type='checkbox'
component={checkBox}
label={tag}
/>
))}
</ul>
I hope this helps you out!

Resources