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

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

Related

update text to API using ReactQuill texteditor

Im trying to update my text in a reactquill texteditor. I also have a input where I can change the title, and it works fine. but when Im trying to set the Text from the text editor it never change.
Im getting the title and text from my update API and it works fine in postman so Im pretty sure its the text editor thats not working with me.
This is what I got so far:
function UpdateDoc() {
const routing = useNavigate();
const params = useParams();
const [name, setName] = useState()
const [text, setText] = useState()
//const quill = useRef();
useEffect(() => {
getDocDetails();
}, [])
const getDocDetails = async () => {
let res = await docModel.getOneDoc(params.id)
setName(res.name)
setText(res.text)
}
const updateDocDetails = async () => {
let res = await docModel.updateOneDoc({ name, text }, params.id)
console.log(res)
routing("/show")
}
return (
<div>
<h2>Update Doc</h2>
<>
<div className='toolbar'>
<button className="button-5" type="button" onClick={updateDocDetails} >
Update
</button>
</div>
<div className='createcontainer'>
<label>Name of Document: </label>
<input
type="text"
placeholder="Add Name of document"
value={name}
onChange={(e) => { setName(e.target.value) }}
name="name"
className="name-text"
/>
<ReactQuill
placeholder="Add text to document"
value={text}
theme="snow"
name="text"
//value="editor.getContents()"
onEditorChange={(e) => { setText(e.target.ref) }} // I FEEL LIKE IS THIS BIT THAT DOS NOT WORK FOR ME
//ref={quill}
/>
</div>
</>
</div >
)
}
export default UpdateDoc

React how to disable submit button until form values are input

I'd like to keep the submit button in my form disabled until the values of the each input are at least one character, not including white space. I tried using trim() and it seems to work until I click submit.
Here is my Form component:
export function Form(props) {
const { form, inputChange, postQuiz } = props;
const onChange = () => {
inputChange()
}
const onSubmit = evt => {
evt.preventDefault()
const question_text_input = document.getElementById("newQuestion");
const question_text = question_text_input.value
const true_answer_text_input = document.getElementById("newTrueAnswer");
const true_answer_text = true_answer_text_input.value
const false_answer_text_input = document.getElementById("newFalseAnswer");
const false_answer_text = false_answer_text_input.value
postQuiz({ question_text, true_answer_text, false_answer_text })
}
return (
<form id="form" onSubmit={onSubmit}>
<h2>Create New Quiz</h2>
<input onChange={onChange} placeholder="Enter question" />
<input onChange={onChange} placeholder="Enter true answer" />
<input onChange={onChange} placeholder="Enter false answer" />
<button
id="submitNewQuizBtn"
disabled={
form.newFalseAnswer.trim().length >= 1
&& form.newTrueAnswer.trim().length >= 1
&& form.newQuestion.trim().length >= 1
? ""
: "disabled"
}
>
Submit new quiz
</button>
</form>
)
}
export default connect(st => st, actionCreators)(Form)
With the code above, the submit button stays disabled until I type at least one character in each input (doesn't count whitespace, like I wanted), but as soon as I click submit I get the error: Uncaught TypeError: Cannot read properties of undefined (reading 'trim').
I don't understand why that happens. Is using trim() on the form Object incorrect?
You can achieve that using two states in your component. One for input and another for the button.
const App = () => {
const [input, setInput] = useState('') // For input
const [isdisabled, setIsDisabled] = useState(false) // For button
// when input is changing this function will get called
const onChange = (e) => {
setInput((prevState) => (e.target.value))
if(e.target.value.trim().length < 1) { // Checking the length of the input
setIsDisabled(true) // Disabling the button if length is < 1
} else {
setIsDisabled(false)
}
}
const onSubmit = (e) => {
e.preventDefault()
// Code...
}
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type='text' placeholder='email' value={input} onChange={onChange} />
<button id='button' type='submit' disabled={isdisabled}>Submit</button>
</form>
</div>
);
}
If you have multiple inputs change the onChange function and input state accordingly.

How can i update data using a form and useRef hooks?

I am building a simple todo app. I am stuck figuring out how to edit those todos using the form. In another component I have a function which I am passing through props which updates the global state. I am able to pass the input fields data that the user selected to be able to update it.
How can i update the submitted values which are passed through props?
const TodoForm = (props) => {
const [error, setError] = useState(null);
const [success, setSuccess] = useState(null);
const titleInputRef = useRef();
const descriptionInputRef = useRef();
function submitHandler(e) {
e.preventDefault();
const titleInputValue = titleInputRef.current.value;
const descriptionInputValue = descriptionInputRef.current.value;
const inputData = {
title: titleInputValue,
description: descriptionInputValue,
id: Date.now(),
completed: false,
};
props.submitInputHandler(inputData);
e.target.reset();
}
return (
<div className="col-span-2 text-center">
<h1 className="text-xl mb-2">Nueva tarea</h1>
<form className="space-y-2" onSubmit={submitHandler}>
<label htmlFor="title" className="block">
Titulo
</label>
<input
ref={titleInputRef}
type="text"
id="title"
/>
<label htmlFor="description" className="block">
Descripcion
</label>
<textarea
ref={descriptionInputRef}
name="descripcion"
id=""
cols="25"
rows="5"
></textarea>
<button >
Click
</button>
</form>
</div>
);
};
I suppose that you want to change the value directly.
In this case you could change the value property of the input reference directly from the ref.current like so:
titleInputRef.current.value = 'Some value'

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

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

Resources