Change input values bases on other input onChange - reactjs

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

Related

How to pass state props to another component

I want to pass a state variable to another component but i don't get it what i'm doing wrong.
I have a component for radio inputs and I need to pass that taskLabel to Form component.
path is components/inputs/index.js
const TaskLabel = (props) => {
const [taskLabel, setTaskLabel] = useState('');
return (
<div label={props.taskLabel} >
<input
type='radio'
name='label'
value='urgent'
onChange={(e) => setTaskLabel(e.target.value)}
/>
<input
type='radio'
name='label'
value='not-urgent'
onChange={(e) => setTaskLabel(e.target.value)}
/>
</div>
);
};
i want to receive the taskLabel value, to use it in submitHandler function.
components/form/index.js
const Form = ({taskLabel}) => {
return (
<form onSubmit={submitHandler}>
<input
type='text'
placeholder='Text here'
className='form-input'
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel taskLabel={taskLabel} />
</form>
)
}
This is what i tried, to pass taskLabel props from label={taskLabel}.
You need to move your state, to Form component, like this:
const [labelProp, setLabelProp] = useState("");
Your TaskLabel component should be
<TaskLabel label={{ labelProp, setLabelProp }} />
That means, you send label, as a prop to TaskLabel component.
In TaskLabel component you need to recive the prosp, by passing to component {label}.
Next, for every input use onChange={(e) => label.setLabelProp(e.target.value)}.
Edited sandbox => https://codesandbox.io/s/laughing-proskuriakova-dhi568?file=/src/components/task-label/index.js
Generally speaking, the concept is "data-down, actions-up". So if you want to pass data down to a lower-level component, you just pass a prop. If you want to update a value from a lower-level component to a higher-level component, you could pass a setter function down as a prop and call that.
Note I just call it taskLevelProp for a little more clarity. You should probably use a better name.
TaskLabel (lower level component)
/* It looks like TaskLabelProp gets passed in from something else.
Otherwise, you would use useState to get your setter function */
const TaskLabel = ({taskLabelProp, setTaskLabelProp}) => {
return (
<div label={props.taskLabel} >
<input
type='radio'
name='label'
value='urgent'
onChange={(e) => setTaskLabelProp(e.target.value)}
/>
<input
type='radio'
name='label'
value='not-urgent'
onChange={(e) => setTaskLabelProp(e.target.value)}
/>
</div>
);
};
Form (higher level component)
const Form = () => {
const [taskLabelProp, setTaskLabelProp] = useState('');
return (
<form onSubmit={submitHandler}>
<input
type='text'
placeholder='Text here'
className='form-input'
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel taskLabel={taskLabelProp, setTaskLabelProp} />
</form>
)
}
Let me know if this answers your question.
EDIT: Made Form use useState. Based off your code, I was assuming you were using useState at the app level.
function App() {
const [task, setTask] = useState("");
const [taskLabelProp, setTaskLabelProp] = useState("");
const handleChange = (e) => {
setTaskLabelProp(e.target.value);
};
const submitHandler = (e) => {
e.preventDefault();
};
return (
<div className="App">
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Text here"
className="form-input"
value={task}
onChange={(e) => {
setTask(e.target.value);
}}
/>
<TaskLabel
onChange={handleChange}
taskLabelProp={taskLabelProp}
taskLabel="select"
/>
<button type="submit">fs</button>
</form>
</div>
);
}
export default App;
const TaskLabel = ({ taskLabel, onChange, taskLabelProp }) => {
return (
<div label={taskLabel}>
<input
type="radio"
name="label"
value="urgent"
onChange={(e) => onChange(e)}
checked={taskLabelProp === "urgent"}
/>
urgent
<input
type="radio"
name="label"
value="not-urgent"
onChange={(e) => onChange(e)}
checked={taskLabelProp === "not-urgent"}
/>
not-urgent
</div>
);
};
export default TaskLabel;

Can't type in textarea when displayed

import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState("")
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={handleSumbit}></textarea>
<input type="submit" />
</form>
)
}
When the text box is displayed I cannot type in it.
What am I doing wrong...?
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState('')
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
<input type="submit" />
</form>
)
}
The textarea is a controlled input - if you are going to tie the value of the <textarea> to the textArea state variable, you need to update that state variable whenever the user changes the input.
Shouldn't the onChange={handleSumbit} of the textarea be
onChange={(e) => setTextArea(e.target.value)}
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState("")
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setTextArea(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={handleSumbit}></textarea>
<input type="submit" />
</form>
)
}
Firstly
You implicitly set the value of your text area using the textArea variable which has an initial state of "" (an empty string).
React automatically refreshes the real DOM from the virtual DOM after every change in state. But the value of your textArea variable doesn't change with this event, so you have to update the state when a value is entered like this:
onChange={(e) => setTextArea(e.target.value)}
After reading your code, I guessed what you wanted to achieve is to prevent the submit button from submitting the form by default and instead logs the name on the console.
I believe this is the code you wanted to achieve:
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState('')
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
console.log(name)
}
return (
<form onSubmit={handleSumbit}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
<input type="submit" />
</form>
)
You can't type here the event not written by you properly, so, you state textarea not updated yet. just needed to change one as a similar name textbox. just replace
<textarea value={textArea} onChange={handleSumbit}></textarea>
to
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
Full code here edited,
import React, { useState } from 'react'
const FormBox = () => {
const [name, setName] = useState('')
const [textArea, setTextArea] = useState('')
const handleSumbit = (e) =>{
e.preventDefault();
// console here form data
}
return (
<form onSubmit={(e)=>handleSumbit(e)}>
<label>Enter your name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<textarea value={textArea} onChange={(e) => setTextArea(e.target.value)}></textarea>
<input type="submit" value="Submit now!" />
</form>
)
I Hope, work fine using this code
Thanks

checkBox once at the time in React

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>
</>
);
};

How to do validation using useRef()

How do I validate input box value using useRef .
Initial validation is not required once user clicks on input box and comes out then it should validate if input box is empty it should show input box cannot be empty.
Codesandbox Link
code i tried. using onBlur
export default function App() {
const name = React.useRef("");
const nameBlurData = (name) => {
console.log("name", name);
};
return (
<div className="App">
<form>
<input
onBlur={() => nameBlurData(name.current.value)}
type="text"
ref={name}
placeholder="Enter First Name"
/>
// show error message here
</form>
</div>
);
}
You can use "useRef" to validate the value of an input field.
No need to use "useState".
Below code is a basic implementation of OP's question
You can replace the "console.log" with your alert component.
import { useRef } from "react";
const ComponentA = () => {
const emailRef = useRef(null);
const passwordRef = useRef(null);
const onBlurHandler = (refInput) => {
if (refInput.current?.value === "") {
console.log(`${refInput.current.name} is empty!`);
}
}
return (
<form>
<input ref={emailRef} onBlur={onBlurHandler.bind(this, emailRef)} />
<input ref={passwordRef} onBlur={onBlurHandler.bind(this, passwordRef)} />
<form/>
)
}
Link to "useRef"
Note: Not tested, code typed directly to SO's RTE
You can use a local state and conditionally render an error message like this:
const [isValid, setIsValid] = useState(true)
const nameBlurData = (name) => {
setIsValid(!!name);
};
return (
<div className="App">
<form>
<input
onBlur={() => nameBlurData(name.current.value)}
type="text"
ref={name}
placeholder="Enter First Name"
/>
{!isValid && <span> input must not be empty </span> }
</form>
Note that you don't really need a ref in this case, you can just use the event object like:
onBlur={(event) => nameBlurData(event.target.value)}
You need to use useState hook to update the value of the name property. Using ref is not ideal here.
Live demo https://stackblitz.com/edit/react-apqj86?devtoolsheight=33&file=src/App.js
import React, { useState } from 'react';
export default function App() {
const [name, setName] = useState('');
const [hasError, setError] = useState(false);
const nameBlurData = () => {
if (name.trim() === '') {
setError(true);
return;
}
setError(false);
};
return (
<div className="App">
<form>
<input
onBlur={nameBlurData}
type="text"
value={name}
onChange={e => setName(e.target.value)}
placeholder="Enter First Name"
/>
{hasError ? <p style={{ color: 'red' }}>Name is required</p> : null}
</form>
</div>
);
}

How to display a ref variable without using state in React?

was wondering if there is any way to directly display the value of a variable from ref without using state, all the examples deal with "alerting" and alert works just fine, I'm trying to figure out to way to display it immediately as well. So, I am simply trying to display the value from the "name" here. Apologies for the x variable naming.
I assume it's not friendly to the DOM.
Thank you.
const UncontrolledExample = () => {
const name = useRef();
let x = '';
const showValue = (e) => {
e.preventDefault();
alert(name.current.value);
x = name.current.value;
return x;
};
return (
<div>
<label>
<input type="text" ref={name}/>
</label>
<button onClick={showValue}>
Display value : {x}
</button>
</div>
)
}
In react, if you want the page to update, you must set state. Your tutorial seems to be showing you how to do uncontrolled components. If you want to keep the input as an uncontrolled component you can, but you still need a state for X. That would look like this:
const UncontrolledExample = () => {
const name = useRef();
const [x, setX] = useState('');
const showValue = (e) => {
e.preventDefault();
setX(name.current.value);
};
return (
<div>
<label>
<input type="text" ref={name}/>
</label>
<button onClick={showValue}>
Display value : {x}
</button>
</div>
)
}
Alternatively, you can turn the input into a controlled component. If you want the display value to only change when the button is pressed, you'll need two states:
const ControlledExample = () => {
const [inputValue, setInputValue] = useState('');
const [x, setX] = useState('');
const showValue = (e) => {
e.preventDefault();
setX(inputValue);
};
return (
<div>
<label>
<input type="text"
value={inputValue}
onChange={(e) => setInputValue(e.currentTarget.value)}
/>
</label>
<button onClick={showValue}>
Display value : {x}
</button>
</div>
)
}
If they should always change simultaneously (ie, without the button), you just need one state:
const ControlledExample = () => {
const [inputValue, setInputValue] = useState('');
return (
<div>
<label>
<input type="text"
value={inputValue}
onChange={(e) => setInputValue(e.currentTarget.value)}
/>
</label>
<p>Display value : {inputValue}</p>
</div>
)
}

Resources