I am using a in a react native functional component and onChange the state does not seem to be updating for "name".
I am console logging the new state using useEffect to check whether or not the state is updated and it is returning undefined as if the input text was never set as the state "name"
function AddTask () {
const [name, setName] = useState('');
useEffect(() => {
console.log(name),name;
})
const updateTaskInfo = event => setName(event.target.value);
return (
<TextInput
onChange={updateTaskInfo}
placeholder="Name"
value={name}
/>
);
}
export default AddTask;
use onChange like that event.nativeEvent.target.value
<TextInput onChange={ event => setName(event.nativeEvent.target.value) } />
or use onChangeText like that
<TextInput onChangeText ={ value => setName(value ) } />
Related
I have a form that has all text elements. How come when I use this change handler function and set the state using the change event listener, it logs what the state was before the change?
const handleChange = event => {
const { name, value } = event.target
setSomeState(prevDateInputs => ({
...prevStateInputs,
[name]: value,
}))
console.log(someState) // ← this logs the value of the state before it was changed
}
In the recent react rfcs release you can use 'use' same as javascript async await method. more details can be found in this link https://github.com/reactjs/rfcs/pull/229
Is it essential to use setState? Could useRef work?
import {useRef} from 'react';
const App = () => {
const inputRef = useRef(null);
function handleChange() {
const {name, value} = inputRef.current;
console.log({[name] : value});
}
return (
<div>
<input
onChange={handleChange}
ref={inputRef}
type="text"
id="message"
name="message"
/>
</div>
);
};
export default App;
But assuming your real use case doesn't involve a console.log, it may not matter if setState doesn't update instantly. In the below example We see the new value displayed on the screen near instantly in the h2 tag even if the console.log shows the old value:
import {useState} from 'react';
const App = () => {
const [message, setMessage] = useState('');
const [someState, setSomeState] = useState('');
const handleChange = event => {
const { name, value } = event.target
setMessage(value)
setSomeState({[name]:value})
console.log('value is:', someState);
};
return (
<div>
<input
type="text"
id="message"
name="message"
onChange={handleChange}
value={message}
/>
<h2>{JSON.stringify(someState)}</h2>
</div>
);
};
export default App;
Some more details here.
Within a child component I have state to store input.
My goal is to pass the input state to the parent component.
//Child component
const [userInput, setUserInput] = useState("");
<TextField value={input} onInput={e => setInput(e.target.value)} />
I tried creating a function to be called on input within the parent function but I cannot seem to get the value "input" passed. What is the correct way to do this? Thanks!
you were approaching correctly. You can pass a function to get the data from the child to the parent. Check this example:
import { useState } from "react";
import "./styles.css";
export default function App() {
const [text, setText] = useState("");
const getInput = (t) => {
console.log(t);
setText(t);
};
return (
<div className="App">
<Component getInput={getInput} value={text} />
<p>{text}</p>
</div>
);
}
const Component = ({ getInput, value }) => {
return (
<>
<h1> Test </h1>
<input type="text" value={value} onChange={(e) => getInput(e.target.value)}></input>
</>
);
};
The parent App is retrieving the text from the child Component passing the function getInput. You only have to decide with event you want to detonate. Of course, this is with input not with TextField. I think that you are using TextField from React Material UI, if that's the case you may check the docs to know how to trigger an event.
You can move the state to the parent component. Then pass the props from the child to the parent.
function Child({
...rest
}) {
return <TextField {...rest} />
}
function Parent() {
const [input, setInput] = useState(''); // '' is the initial state value
return (
<Child value={value} onInput={e => setInput(e.target.value)} />
)
}
I finally figured this out.
// This is in the parent component
const [userInput, setUserInput] = useState("");
// Step 1: Create a function that handles setting the state
const inputHandler = (userInput) => {
setUserInput(userInput);
}
<PhaseTwoTemplate onInput={inputHandler} />
//Step 2: Add a function that calls the handler
...
// This is the child component PhaseTwoTemplete.js
const [input, setInput] = useState("");
// This second state holds the input data for use on child component
// It also is an easy way to hold the data for the parent function.
<TextField
onChange={e => setInput(e.target.value)}
value={input}
onInput={onInputHandler}
/>
// Step 3: Pass the user input to the parent
const onInputHandler = () => {
props.onInput(input);
}
When the user focuses on input I want to change the variant on the TextField. Bellow snippet does that, but the input loses focus. you need to click again on input in order to focus and write some text inside
import React, { useState } from 'react'
import { TextField } from '#material-ui/core'
const App = () => {
const [name, setName] = useState('')
const [focus, setFocus] = useState(false)
return <TextField
variant={focus ? 'outlined' : 'standard'}
onFocus={(e) => setFocus(true)}
value={name}
name='name'
onChange={(e) => setName(e.target.value)} />
}
sandbox: https://codesandbox.io/s/material-ui-dynamic-variant-7up6q?file=/demo.tsx
My understanding is the following:
TextField component re-renders with new props and is creating a new input element to display while destroying the old one. In this way, the user needs to do 2 clicks on input before texting.
I tried with onClick also, leading to the same result.
Is there a way to obtain these results without losing the focus on input?
Use "useRef" for focusing the input, inputRef prop will help you to set ref. And useEffect to track and update.
const App = () => {
const [name, setName] = useState("");
const [focus, setFocus] = useState(false);
const inputRef = useRef(null);
const onFocus = () => {
setFocus(true);
};
const onBlur = () => {
setFocus(false);
};
useEffect(() => {
if (focus) {
inputRef.current.focus();
}
}, [focus]);
return (
<TextField
variant={focus ? "outlined" : "standard"}
onFocus={onFocus}
onBlur={onBlur}
value={name}
inputRef={inputRef}
name="name"
onChange={(e) => setName(e.target.value)}
/>
);
};
export default App;
You can check demo here:
Link - https://codesandbox.io/s/material-ui-dynamic-variant-forked-8pbdi?file=/demo.tsx
I am unable to update my react hooks state.
So this is what I am doing (this is a minified relevant code).
export const Signup = (props) => {
const key= 'randomKey'
const onTextChangeHandler = (text) => {
console.log(key)
setPayloadData[key] = text
console.log(payload)
}
const [payload, setPayloadData] = useState({})
return (
<View>
<TextInput
placeholder={placeHolder}
number={number}
style={[{color: defaultColor, borderColor: defaultColor}, styles.defaultTextInputStyle, templateStyle]}
onChangeText={text => onTextChangeHandler(text)}
value={payload[key]}
/>
</View>
)
}
here, In the above code, notice
const onTextChangeHandler = (text) => {
console.log(key)
setPayloadData[key] = text
console.log(payload)
}
Here text is coming out to be whatever I typed. console.log of the key is returning the randomKey but
console.log(payload)
Is coming out to be undefined. Can anyone help me in figuring out what I am doing wrong?
setPayload is a function, not an object. What you are actually doing is assigning a new field to the function, the payload remains unchanged, since the function responsible for updating it is not being called.
setPayloadData[key] = text; // the function object mutation occures
Solution: simply invoke it as a function and pass the argument you want:
setPayloadData({ [key]: text });
Example: Update state using useState hook
Update props value and HOC components accordingly
import React, { useState } from 'react';
const Signup = (props) => {
const key= 'userKeyboardStrokes'
const onTextChangeHandler = (event) => {
setPayloadData({ [key]: event.target.value })
}
const [payload, setPayloadData] = useState({})
return (
<React.Fragment>
<input
type="text"
onChange={text => onTextChangeHandler(text)}
/>
</React.Fragment>
)
}
module.exports = Signup;
Output Result:
{
userKeyboardStrokes: "user input on object"
}
Playground Example:
https://stackblitz.com/edit/react-npytvn?file=testing.js
setPayloadData is a setter, it should be setPayloadData(newData) to update the state.
Since I'm learning how to build React forms with hooks, I went through the 3 quicks posts that culminate with this one. Everything is going well until I get to the last step when you create your custom hook with:
function useFormInput(initialValue) {
const [value, setValue] = useState(initialValue);
function handleChange(e) {
setValue(e.target.value);
}
return {
value,
onChange: handleChange
};
}
The Input is:
const Input = ({ type, name, onChange, value, ...rest }) => (
<input
name={name}
type={type}
value={value}
onChange={event => {
event.preventDefault();
onChange(name, event.target.value);
}}
{...rest}
/>
);
And the Form is:
const Form = () => {
const email = useFormInput("");
const password = useFormInput("");
return (
<form
onSubmit={e =>
e.preventDefault() || alert(email.value) || alert(password.value)
}
>
<Input
name="email"
placeholder="e-mail"
type="email"
{...email}
/>
<Input
name="password"
placeholder="password"
type="password"
{...password}
/>
<input type="submit" />
</form>
);
};
So in useFormInput() Chrome complains about
TypeError: Cannot read property ‘value’ of undefined at handleChange
which I'm pretty sure is pointing me to
function handleChange(e) {
setValue(e.target.value);
}
If I console.log(e) I get 'email', as expected (I think?), but if I try console.log(e.target) I get undefined. So obviously e.target.value doesn't exist. I can get it working by just using
setValue(document.getElementsByName(e)[0].value);
but I don't know what kind of issues this might have. Is this a good idea? Are there drawbacks to getting it to work this way?
Thanks
The issue comes from the onChange prop in the Input component
onChange={event => {
event.preventDefault();
onChange(name, event.target.value);
}}
you're calling onChange like this onChange(name, event.target.value); (two arguments, the first one is a string), while in your custom hook you define the callback like this
function handleChange(e) {
setValue(e.target.value);
}
it's expecting one argument, an event.
So either call onChange with one argument (the event) :
onChange={event => {
event.preventDefault();
onChange(event);
}}
or change the implementation of the callback.
Try this out:
const handleChange = e => {
const { inputValue } = e.target;
const newValue = +inputValue;
setValue(newLimit);
};
Had this issue with a calendar picker library react-date-picker using Register API. Looking at the documentation found out that there's another way of handling components that don't return the original event object on the onChange function using the Controller API.
More details on Controller API Docs
Example:
/*
* React Function Component Example
* This works with either useForm & useFormContext hooks.
*/
import { FC } from 'react'
import { Controller, useFormContext } from 'react-hook-form'
import DatePicker,{ DatePickerProps } from 'react-date-picker/dist/entry.nostyle'
const FormDateInput: FC<Omit<DatePickerProps, 'onChange'>> = ({
name,
...props
}) => {
const formMethods = useFormContext()
const { control } = formMethods ?? {}
return (
<Controller
render={({ field }) => <DatePicker {...props} {...field} />}
name={name ?? 'date'}
control={control}
/>
)
}
export default FormDateInput