React: React Input Field not editable after i set data to state? - javascript

I don't know what might be wrong here, but i am following a tutorial and writing the same lines of code, but it seems that i am getting an error when i add this block of code.
setTeacherLoginData({
...teacherLoginData,
[event.target.name]:event.target.value
});
i am thinking that my error is related to this.
Since the value attribute is not updating, it's not possible to edit the given input field. You can solve this by adding an onChange event and the value attribute to the input field
this is the code i have written so far
const [ teacherLoginData, setTeacherLoginData ] = useState({
email: '',
password: '',
});
const handleChange = (event) => {
setTeacherLoginData({
...teacherLoginData,
[event.target.name]:event.target.value
});
};
const submitForm = () => {
console.log(teacherLoginData);
};
return (
<input value="{teacherLoginData.email}" onChange="{handleChange}" type="text" className="form-control" />
<input value="{teacherLoginData.password}" onChange="{handleChange}" type="password" className="form-control" />
<button onClick="{submitForm}" className="btn btn-primary">Login</button>
)

In addition to the issues that peetzweg's answer mentions, you are missing name attributes on your form inputs. This means that the event.target.name in your handleChange function will not be populated.

You are passing literal strings into the props of your html <input/> and <button/>.
This makes sense in vanilla HTML to set attributes of the <input/> and <button/> tags, but this is not what you want in React, which uses JSX instead of HTML syntax.
HTML Example:
<input value="{teacherLoginData.email}" onChange="{handleChange}" type="text" className="form-control" />
In React we write JSX which is something like JS + HTML.
Here we speak of props instead of attributes for a html element. You pass props similar to html, however you can pass javascript objects as well using the {} braces.
JSX:
<input value={teacherLoginData.email} onChange={handleChange} type="text" className="form-control" />
Noticed I remove the "" from the value and onChange prop to actually pass the functions instead of a string containing "teacherLoginData.email".
If you use quotes you are passing a string instead of the actual javascript reference of a function. For some props it's intended to pass a string i.e. the type & className prop of this <input/>.
Here is a link to the docs of JSX to get you familiar with it:
https://reactjs.org/docs/jsx-in-depth.html

Related

React: Warning, a component is changing an uncontrolled input to be controlled

I'm using Google maps address autocomplete in my React app. It works by hooking into an input element, watching for changes, and providing a dropdown location select.
Relevant code:
<InputGroup hasValidation className="mb-3">
<FormControl id="autocomplete"/>
</InputGroup>
useEffect(() => {
// only specify the fields we need, to minimize billing
const options = {"fields": ["address_components"]}
const autocompleteElement = document.getElementById("autocomplete")
if(autocompleteElement) {
autocomplete.current = new google.maps.places.Autocomplete(autocompleteElement, options);
const listener = autocomplete.current.addListener("place_changed", placeSelected);
return function cleanUp() {
google.maps.event.clearInstanceListeners(listener);
}
} else {
// nothing to do yet
return;
}
});
However, I'm getting a warning in the browser console:
Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component
Seems obvious enough- the autocomplete functionality is changing the input itself as opposed to using react state to make a controlled component. However that's the way I want it. Is there a way I can silence this error? I've tried adding an empty defaultValue and an empty onChange function, but still got the error. Thanks in advance!
(There were a few questions with the same issue, but nothing about deliberately disabling the warning)
I have faced such warnings on a couple of projects here is one of the causes and solution.
const [value, setValue] = useState("");
<input value={value} onChange={inputHandler} />
From the code above notice that the state initial value is "", check yours. Its possible you are using null or empty value.
You need to change it to empty string and that warning will disappear.
Let me know if its helpful.
We cleared this error by simply adding default values to our form inputs:
<p style={{ fontWeight: 'bold' }}>Devices: </p>{' '}
<Select
isMulti
value={mapValuesToSelect(devices) || []}
// this one rigth here ^^^^^
onChange={(e) => editDevicesMultiSelect(e)}
or simple input:
<Input
type="text"
value={code || ''}
// ^^^^^
P.S. we also have a handleSelectOnClose function:
<Button onClick={handleUnselect}>
CLOSE
</Button>
const handleUnselect = () => {
dispatch(setCurrentDesk(undefined));
};
Use a regular uncontrolled html input instead of one of the controlled react-bootstrap inputs.
You can use a ref to refer to the input.
<InputGroup hasValidation className="mb-3">
<input
defaultValue="Belgium"
type="text"
ref={this.autocomplete} />
</InputGroup>
More info on uncontrolled inputs and ref usage here:
https://reactjs.org/docs/uncontrolled-components.html
You can try using a third party custom package like:
React Places autocomplete.
This package provides an option to use controlled input, as well as other props to customise styling and other methods
const [value, setValue] = useState(null);
<GooglePlacesAutocomplete
selectProps={{
value,
onChange: setValue,
}}
/>
You need to give an initial value and an onChange method. I'd probably use a hook to make this easier to manage. You could then use the useEffect() hook to call the API when the value of inputText changes.
const [inputText, setInputText] = useState('');
useEffect(() => {
if (inputText.length > 0) {
... call the api
}
},[inputText])
<InputGroup hasValidation className="mb-3">
<FormControl id="autocomplete" value={inputText} onChange={(event) => {setInputText(event.target.value}}/>
</InputGroup>
as Blessing Ladejobi said its beacuse of
<input value={myValue} onChange={inputHandler} /> and myValue=null
solution is define a default value for myValue (like myValue="")

ReactJS autocomplete from React Bootstrap not working

I'm trying to build an autocomplete search field, using this form component from React Bootstrap, which is rendered as a input by the browser.
Here's what I did in my React component:
<FormControl
id="frenchToEnglishInput"
placeholder="type a word..."
aria-label="Recipient's username"
autocomplete="on"
data={frenchToEnglishWords}
onChange={this.fetchFrenchToEnglish}
renderItem = {item => {
return (
<div>
{item}
</div>
);
}}
/>
the frenchToEnglishWords array is declared outside the component as a var, as I intend to update it as I type some value into the input field.
Now here is the function that triggers the onChange event :
fetchFrenchToEnglish = async () => {
if(document.getElementById("frenchToEnglishInput").value!==''){
axios.get(dictionaryURIs.english.French_English+""+document.getElementById("frenchToEnglishInput").value)
.then(response => {
frenchToEnglishWords = response.data
})
}
}
The request is made from MongoDb, after setting up an autocomplete index on a collection, but this part works fine.
My question is, why is the only "autocomplete" I'm getting is the one made of the previous words I've typed ?
Or maybe the array I'm using as input data must be a const (as I've seen in many examples) and not a var ?
When I do type in some word, I do not get any autosuggestion from the frenchToEnglishWords, which is being updated from the DB.
You need to use State!
This is not working because the data field is not a State, you need to bind the fetchFrenchToEnglish function to the data state.
But first of all, there's no reason to use var, because the most differences between them is just scope and immutability, here is more about it.
Also, you can use hooks like useState and useRef to no use getElementById.

Two way binding for Formik Field and custom component in React

I am trying to pass my own functional component as a component attribute to a Formik Field in React. The problem is I don't know how to bind the Formik Field's value with the value in my custom component. Here's what I tried:
Form.js
// other Formik Form code...
<Field
className="form-control"
name="NetWeight"
component={IntegerComponent}
></Field>
//...
IntegerComponent.js
function IntegerComponent({ field, className }) {
const onChangeHandler = event => {
const returnVal = (event.target.validity.valid) ? event.target.value : inputValue;
setInputValue(returnVal);
};
return <input
type="text"
pattern="[0-9]*"
className={className}
onChange={onChangeHandler}
value={inputValue}
/>
}
I want to bind Formik's field.value which I am destructuring from the props, to my NumberComponent's input's value. I tried doing field.value = returnVal but it didn't work as well. I know I can use onBlur and onChange handlers for above purpose than creating my functional component but the way my project is built, if I can make this work, it will help reducing a lot of redundant code. Any thoughts or suggestions?

Read value of imported form component upon submit (without storing in state)

I developed a component for ReactJS as to be used as a form item in conjunction with Antd's form. But, the onFinish callback function returns undefined for the value of my custom component. Probably, Antd's form is not being able to retrieve the value from my component. That does not happen when I am only using Antd components as form items.
On the example below, MultipleEntry is the component I have developed. MultipleEntry has a nested TextArea component.
function Sandbox(props) {
return (
<>
<Form onFinish={(values) => console.log(values)}>
<Form.Item name={'myComponent'} >
<MultipleEntry />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">Submit</Button>
</Form.Item>
</Form>
</>
);
}
function MultipleEntry(props) {
const [value, setValue] = useState([]);
const Split = string =>
{
setValue(String(string).split(';'))
}
return (
<TextArea
onChange={(e) => {Split(e.target.value)}}
/>
);
}
I thought about two alternatives here:
Storing the values of MultipleEntry in its internal state.
Storing the values of MultipleEntry on the parent component.
But, I dont want to store the values anywhere on the client's state, since the data inside the MultipleEntry component would be too big and impactful for performance.
How can I use Antd form's API to make it read the value of MultipleEntry as a form field, and populate the input parameter of onFinish?
Antd's FormItem behaves like a high-order component and passes some props to the child component.
So, if you are using any HTML form field elements like input, then FormItem will pass the onChange and value as props to input. Hence FormItem will control the value and onChange event of that element.
But having said above you will not be able to use the styling if some validation error is there in the FormItem.
Similarly Antd's component also usages native HTML form field elements and usages value and onChange. But on top of that, you will get the styles if there are any validation errors.
Here it comes your specific case, you can use onChange and value from props and utilize the same as following
function MultipleEntry(props) {
const Split = e => {
e.target.value = String(e.target.value).split(",");
props.onChange(e);
};
return <input value={props.value} onChange={e => Split(e)} />;
}
If you are using any native HTML form elements then just split the props and pass it across the element like below
function MultipleEntry(props) {
return <input {...props} />;
}
And for splitting you can use getValueFromEvent and then split the value there.
Here is the link for the modified sandbox to especially solve your problem https://codesandbox.io/s/agitated-lake-65prw

React refs how are they used, and when are they used?

Hello and thank you for reading this question!
I have been learning React for some weeks and I have difficulties trying to understand how refs can get React's instance and put it into a JS variable.
For example we could discuss the documentation's example:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
this.textInput.focus();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
I understand that the ref gets the input element which will be rendered and stores it into a class field using this.textInput.
However I do not understand why the parameter being passed to the refs is (input) what could happen if there were jsx tags nested? For example two inputs?
Also is there not a clear way to reference the elements being created with React render/return? I am talking about something like object oriented programming: className.instanceName or creating instance from the HTML elements with: new elementName().
Thank you for your help!
React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.
When you write
<input
type="text"
ref={(input) => { this.textInput = input; }} />
React extracts the ref attribute and invokes a callback after the component is mounted. In that callback function react passes the instance of the input, which is what you get as the parameter here. Think of the above as a function
<input
type="text"
ref={this.callback} />
and that callback will look like
const callback = (input) => {
this.textInput = input;
}
According to the docs:
When the ref attribute is used on an HTML element, the ref callback
receives the underlying DOM element as its argument.
Regarding your next question:
However I do not understand why the parameter being passed to the refs
is (input) what could happen if there were jsx tags nested
The parameter being passed to div is just referenced as input in your example, you can call it anything you want, like input, inputRef, instance
In multiple jsx tags are nested, the ref is applied on the element on which ref attribute is passed. For instance
<div ref={this.getRef}>
<div>Hello React</div>
</div>
The ref gets the instance of is applied to the outer div from which you can access the child elements.
Codesandbox
Also is there not a clear way to reference the elements being created
with React render/return
Well refs is a way provided by React to reference, elements being created. However you should only use refs when
Managing focus, text selection, or media playback.
Triggering imperative animations.
Integrating with third-party DOM libraries.
Most often, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props. For example if you wish to change the class on an element, instead of getting an access to the element and changing it class, you would pass the dynamic prop to it instead like
<div className={this.props.className} />
Or as a matter of fact, use state to make necessary updates
To explain what is happening with the ref tag, let's break it down into smaller pieces...
This block:
<input
type="text"
ref={(input) => { this.textInput = input; }} />
Says to call this (input) => { this.textInput = input; } when this input field is mounted and unmounted. The (input) is just a parameter name, and you could call it whatever you want. So you could rewrite it as:
<input
type="text"
ref={(myinputfield) => { this.textInput = myinputfield; }} />
And it will do the same thing. In both case, input and myinputfield both reference the text field on which the ref attribute was defined.
For your second question,
Also is there not a clear way to reference the elements being created
with React render/return? I am talking about something like object
oriented programming: className.instanceName or creating instance from
the HTML elements with: new elementName().
The react model is a bit different. state is the primary way to have components interact with each other, rather than one component calling another. It's not entirely clear what you're trying to do, but when you want to update one component based on some action another component does, you would typically update the state, which would re-render the components with the new state.
You can still lookup other components in the DOM, but I'd encourage you to think more in the react model that uses state to update components.

Categories

Resources