How do I update the default useSate value from a html input? - javascript

This Is a simple question. I have a React useState hook,
const [seconds, setSeconds] = useState(0);
how would I be able to update the useState default of 0 to any number I enter, from some kind of a text box or Input in HTML?
Thanks in advance.

You need to add a change event in the input then add the function to handle the input change. like this example.
export default function App() {
const [seconds, setSecond]= useState(0);
const handleSeondChange = (event)=>{
setSecond(event.currentTarget.value);
}
return (
<div className="App">
<input name ="seconds" value={seconds} onChange={handleSecondChange}/>
</div>
);
}

Within an input tag include an onChange handler. For example, <input onChange={(event) => setSeconds(event.target.value)} value={seconds}/>. You're dealing with a controlled input here, so make sure you include the value tag within the input like I included above.

Related

react-jsonschema-form input box out of focus when ObjectFieldTemplate is used

I have rjsf version ^5.0.0-beta.10 installed in package.json and am able to render a proper Form using react-jsonschema-form. The problem is that I'm using ObjectFieldTemplate and every time I enter a character in one of the string input boxes, the box goes out of focus and I have to click on the box again to be able to type anything.
I have read https://github.com/rjsf-team/react-jsonschema-form/issues/2106, which suggested me to move the ObjectFieldTemplate outside of the custom Form definition. I did that and it does not work. I have also read Custom widget with input loses focus in react-jsonschema-form when formData is passed as a prop to the form, which is an advice about setting state, but I'm using functional components rather than class components, so I'm not sure if it's applicable.
The code looks like:
import validator from "#rjsf/validator-ajv6";
import Form from "#rjsf/mui";
const ObjectFieldTemplate = (props) => {
// some logic to be computed
return (
<div>
<h3>{props.title}</h3>
<p>{props.description}</p>
{props.properties.map(function (field) {
// logic to determine the style
return (<fieldset style={style} key={uuidv4()}>{field.content}</fieldset>);
})}
</div>
);
}
const JsonSchemaForm = (props) => {
// define schema and uiSchema
const onSubmit = ({formData}, e) => {
// some logic
}
const onError = (errors) => {console.log(errors);}
return (<Form
schema={schema}
validator={validator}
formData={data}
uiSchema={uiSchema}
onSubmit={onSubmit}
onError={onError}
templates={{ ObjectFieldTemplate }}
/>);
}
Solved. I'm not sure why, but it appears that setting key={uuidv4()} is an expensive computation step that forces the input box to be out of focus.

How to change a class based on focus and change in an input form in React

I have a situation where I want to append a class called shrink to the label text below (Display Name) when I click or type in the input box.
My code is below:
const FormInput = ({ label, ...otherProps} ) => {
let labelClassName = 'formInput-label';
const addLabelClassName = () => {
labelClassName = `${labelClassName} shrink`;
console.log(labelClassName, 'labelClassName inside')
}
console.log(labelClassName, 'labelClassName outside')
return (
<div className="group">
{label &&
<label
className={labelClassName}
>{label}</label>
}
<input onFocus={addLabelClassName } onChange={addLabelClassName } className="formInput" {...otherProps} />
</div>
)
};
My question:
Why does when I focus/ type, at first, React outputs the correct classnames for labelClassName inside as formInput-label shrink, but immediately changes it back to formInput-label at the labelClassName outside position? How would I fix this?
I have also tried to change the code to using the UseState approach like below:
const FormInput = ({ label, ...otherProps} ) => {
const [interaction, setInteraction] = useState('');
let labelClassName = 'formInput-label';
const onInteracting = () => {
setInteraction('interacting')
}
if(interaction === 'interacting') {
labelClassName = `${labelClassName} shrink`;
}
return (
<div className="group">
{label &&
<label
className={labelClassName}
>{label}</label>
}
<input onFocus={onInteracting} onChange={onInteracting} className="formInput" {...otherProps} />
</div>
)
};
And this will append the correct class shrink to labelClassName but I'm not able to take that off when I click outside of the input/form. How may I fix this?
Thank you a ton!
The second approach is a better way because with changing state you will trigger component rerendering (the first approach will never re-render component).
In the second approach, you can take advantage of onBlur event and create a handler which will set the state to the default value. Something like this. You don't need onChange to setIntercation
...
const handleBlur = () => {
setInteraction("");
};
...
and then in input, you have to set up onBlur prop. onChange should not do the same thing as onFocus already does.
....
<input
onFocus={onInteracting}
onBlur={handleBlur}
className="formInput"
{...otherProps}
/>
....

React Error: Too many re-renders. while using arrow function

I am making a calculator in react in which i made buttons for numbers and when button "7" is pressed then in the input field 7 is added.
My approach:
I am using useState to do this.
I made an arrow function funinpval which takes takes number as string in argument then i am using this function with different buttons onclick handler by passing respective numbers as arguments. But I am getting error
import React from 'react'
import { useState } from 'react';
export const Calculator = () => {
const [inpval, setInpval] = useState("")
const funinpval = (num) => {
setInpval(inpval + num)
}
return(
<>
<input type="text" value={inpval}>
<button onClick={funinpval("7")}>7</button>
<button onClick={funinpval("8")}>8</button>
</>
)
Can anyone please help
<button onClick={funinpval("7")}>7</button>
<button onClick={funinpval("8")}>8</button>
You are not waiting the user to click the buttons to execute the functions, they are instead executed every render phase, directly. Which mean that the component render -> state update -> new re-render -> new state update -> ...
To fix it:
<button onClick={() => funinpval("7")}>7</button>
<button onClick={() => funinpval("8")}>8</button>
There is a syntax error in how you are providing the event handlers.
You have to provide event handlers sonething like:
<button onClick={() => funinpval("7")}>7</button>
<button onClick={() => funinpval("8")}>8</button>
Simply writing onClick={funinpval("7")} will immediately call the function while rendering which sets the state. When state got updated then the component re-renders. Then again while re-rendering, this function got called and so on.
onClick={funinpval("7")}
will return the result of calling that function to the listener rather than a reference to the function that the listener can call. So you're setting state immediately with those two buttons which is causing the render which is calling the function again which is setting the state again... infinity!
In this example I pick up the textContent of the button and use that to set the new input state, and then you can simply just pass the reference to the function to the handler and let the function deal with how state is set.
const { useState, useEffect } = React;
function Calulator() {
const [inpval, setInpval] = useState(0);
function funinpval(e) {
// Grab the `textContent` of the button and
// relabel it to `num` making sure to coerce the
// text to a number first
const { textContent: num } = e.target;
setInpval(inpval + Number(num));
}
return(
<div>
<input type="text" value={inpval} />
<button onClick={funinpval}>7</button>
<button onClick={funinpval}>8</button>
</div>
)
};
// Render it
ReactDOM.render(
<Calulator />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

How can I make my HTML update when I press the update button?

function setTodoInfo(id) {
let todoInfo = todoInfoRef.current.value
if(todoInfo === "") return
todo.info = todoInfo
todoInfoRef.current.value = null
}
<>
<h1 className="delete-button"> hi, {todo.info} </h1>
<form>
<input type="text" ref={todoInfoRef}/>
</form>
<button onClick={closeInfo} className="delete-button" > Close </button>
<button onClick={setTodoInfo}> Set Info</button>
</>
When I click the set Info button its updating the info property on the todo, but it doesn't display it when you click, you have to close it and reopen it to see the updated info
react uses reference to be able to see it should or not rerender. using refs means the reference doesnt change...
as pointed, you should really see the docs on how to make it the "react way"
if you really need to make with references, then you could add some "render" function.
put in a useState a integer or something else, then call setState to change its value... that should force a render.
function useForceUpdate(){
const [value, setValue] = useState(0); // integer state
return () => setValue(value => value + 1); // update the state to force
}
(inside functional component)
const forceUpdate = useForceUpdate();
call forceUpdate where needed

React: Insert value at cursor

I need to add a value (from the dropdown), this will be added in the input field 'at the position of the cursor':
import { useState } from "react";
import "./styles.css";
export default function App() {
const [cur, setCur] = useState("");
const [state, setState] = useState("");
const [dropVal, setDropVal] = useState("");
const handleChange = (e) => {
setState(e.target.value);
// gives cursor index
// this only shows cursor position if user types
// I need to track the position of the cursor and add dropVal there
setCur(e.target.selectionStart);
};
return (
<div className="App">
<input onChange={(e) => handleChange(e)} value={state} />
<select onChange={(e) => setDropVal(e.target.value)} >
<option>ONE</option>
<option>TWO</option>
</select>
</div>
);
}
I tried this, which is incomplete, couldn't find a way to implement it anywhere.
Would appreciate the help, thanks in advance!!
What you are looking for is the selectionStart and selectionEnd properties on an input field.
Basically, you can attach an onBlur listener on your input field and inside it you can access the selectionStart property and save it in state.
Blur means that the input field has lost its focus (meaning you have clicked somewhere outside - like on the dropdown in our case). So once the onBlur is triggered, the selectionStart refers to where your cursor was while the input was still in focus.
Later you can use this value to break the string and add whatever you want (option value in this case) at the position of the cursor.
const onBlur = (e) => {
setCur(e.target.selectionStart);
};
Have a look at this code sandbox

Categories

Resources