How to update state on disabled field in react - javascript

I am trying to showing default value and want to disable it field . Values is showing successfully but did not update it state . Could someone please help me how to update state on disable field . I really tried hard but didn't find any solution .
Thanks
Code
componentWillReceiveProps(nextProps) {
const { projectData } = nextProps;
this.setState({
project: projectData,
});
}
componentDidMount() {
const { stan_rate_Per_sqft, category_charges, project } = this.state;
console.log("##### data", stan_rate_Per_sqft, category_charges);
if (
project &&
project.category_charges_apply &&
project.category_charges_apply === "yes"
) {
this.setState({
rate_Per_sqft: stan_rate_Per_sqft * parseInt(1 + category_charges),
});
}
}
In Render Method
<td>
<input
type="text"
className="inputStyle"
name="rate_Per_sqft"
value={rate_Per_sqft}
disabled={true}
placeholder="Category Charges"
/>
</td>

Your component is always disabled since it's hardcoded to true. If you want it to have a dynamic state you'll need to add key to your class state.
...
constructor(props) {
super(props);
this.state = { isDisabled: true }
}
...
Now, in your input field, you may use this state...
<input ... disabled={this.state.isDisabled} />
When isDisabled is set to false (using setState), the field will be enabled again and vice versa.

The disabled attribute on an <input> element works by passing in a boolean value. A truthy value will disable it, a falsy value will enable it.
With that in mind we could use the negated value of rate_Per_sqft to enable the input element. Perhaps something like this:
class App extends React.Component {
state = {
rate_Per_sqft: null
}
componentDidMount() {
// Simulate asynchronous operation
setTimeout(() => {
this.setState({ rate_Per_sqft: 550 })
}, 1500)
}
render() {
const { rate_Per_sqft } = this.state
return(
<div>
{!rate_Per_sqft && <span>Calculating charges..</span>}
<input
type="text"
name="rate_Per_sqft"
value={rate_Per_sqft}
disabled={!rate_Per_sqft}
placeholder="Category Charges"
/>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Note: I wasn't sure if you wanted the form disabled or enabled by default. So, I disabled it. Also, I simplified the code to keep the example short and simple.

Related

this.setState() not changing value (not an asynchronous update issue)

Just a note, this question is NOT an asynchronous update problem (at least, I don't think it is).
I have a class component with the following content (heavily simplified to get right to the issue):
constructor(props) {
super(props);
this.state = {
aSelected: false;
bSelected: false
}
}
handleCheckboxChange = (e) => {
const { checked, value } = e.target;
console.log( 'checked: ', checked );
if(value=="a") {
this.setState( {aSelected: checked}, () => {
console.log('aSelected: ', this.state.aSelected);
console.log("---")
});
}
if(value=="b") {
this.setState( {bSelected: checked}, () => {
console.log('bSelected: ', this.state.bSelected);
console.log("---")
});
}
}
Somewhere inside the render return, I have this:
<input>
type="checkbox"
value="a"
onChange={this.handleCheckboxChange}
checked={this.state.aSelected}
disabled={ (this.state.aSelected || (!this.state.aSelected && !this.state.bSelected) ) ? false : true}
</input>
<input>
type="checkbox"
value="b"
onChange={this.handleCheckboxChange}
checked={this.state.bSelected}
disabled={ (this.state.bSelected || (!this.state.aSelected && !this.state.bSelected) ) ? false : true}
</input>
Here is the output logged in Chrome Developer Tools. As you can see, "checked" is toggled appropriately each time I selected and unselect the checkbox. However, the state of "selected" (should say "aSelected") is never changed and always has the initial state value of false. Anyone know why the value of "selected" (should say "aSelected") is never changed?
Edit: My goal is to create two checkbox items, where the user can only select ONE or select NONE. While one is selected, the other should be disabled.
When you call setState to update the state, React re-renders the component, which resets the checkbox back to it's default (i.e. unchecked) state.
You'll need to use the current state to manage the checkbox as well. The JSX should look something like:
<input
type="checkbox"
checked={this.state.aSelected}
onChange={this.handleCheckboxChange}
/>
In React's terms, this is what's known as a "controlled component" because React is fully responsible for keeping up with the input's state. Read more in the docs here:
https://reactjs.org/docs/forms.html#controlled-components
vs
https://reactjs.org/docs/uncontrolled-components.html
Edit to match the question's edits:
In your render function, be sure you're using this.state.aSlected. Note, you also still need the checked={this.state.aChecked} attribute as well, otherwise the checkbox will be unchecked on the next render.
Like:
<input
type="checkbox"
value="a"
onChange={this.handleCheckboxChange}
checked={this.state.aSelected}
// added for clarification *
disabled={this.state.aSelected || (!this.state.aSelected && !this.state.bSelected) ? false : true}
/>
Edit with Working Example
Here's a working CodeSandbox example where checking one checkbox disables the other:
class CheckboxComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
aSelected: false,
bSelected: false
};
}
handleCheckbox = (event) => {
if (event.target.name === "boxA") {
this.setState({ aSelected: event.target.checked });
} else if (event.target.name === "boxB") {
this.setState({ bSelected: event.target.checked });
}
};
render() {
let aDisabled = this.state.bSelected && !this.state.aSelected;
let bDisabled = this.state.aSelected && !this.state.bSelected;
return (
<div>
<label>
<input
type="checkbox"
name="boxA"
checked={this.state.aSelected}
onChange={this.handleCheckbox}
disabled={aDisabled}
/>
Checkbox A
</label>
<br />
<br />
<label>
<input
type="checkbox"
name="boxB"
checked={this.state.bSelected}
onChange={this.handleCheckbox}
disabled={bDisabled}
/>
Checkbox B
</label>
</div>
);
}
}

React Checkbox Controlled Component

This is driving me crazy. I have no problem with select drop downs and text fields, but for some reason, I cannot get checkboxes working in a controlled fashion. That it is I want them to 'toggle' and listen to this event in a parent component.
I understand there is a 'checked' property for inputs of type checkbox. Selecting a checkbox gives it a value of 'on'. I take this 'on' value and convert it to true or false, and update the component accordingly.
For some reason, I cannot get this to work, either it is always selected, or it is never selected (if I switch the boolean switch).
export class ControlledCheckbox extends React.Component {
constructor(props) {
super(props);
this.state = {
select: false,
};
}
render() {
console.info("this.state.select - " + this.state.select);
let sel = false;
if (this.state.select !== "on") {
sel = true;
} else {
sel = false;
}
return (
<div>
<input
type="checkbox"
checked={sel}
onChange={this.handleChangeCheckbox}
/>
</div>
);
}
handleChangeCheckbox = (e) => {
console.info("here e.currentTarget.value " + e.currentTarget.value);
this.setState({
select: e.currentTarget.value,
});
//call passed through callback here
};
}
value serves a different purpose for checkbox inputs and you should not use it to define your state's value. You need to take a look at the e.currentTarget.checked instead.
export class ControlledCheckbox extends React.Component {
constructor(props) {
super(props);
this.state = {
select: false,
}
}
handleChangeCheckbox = e => {
this.setState({
select: e.currentTarget.checked // <--
})
}
render() {
return (
<div>
<input type="checkbox"
checked={this.state.select}
onChange={this.handleChangeCheckbox} />
</div>
);
}
}
If you are working with multiple inputs (not only checkboxes) you can follow the approach suggested by react docs, where you can cover multiple input types with only one setState. Keep in mind to define a name in this case, so you can separate your inputs:
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<div>
<input type="checkbox"
name="hasValue"
checked={this.state.select}
onChange={this.handleChangeCheckbox} />
</div>
);
}
Your question is about controlled inputs, however your checkbox isn't controlled yet. You rely on the value stored inside checkbox, not inside the state.
this.setState({
select: e.currentTarget.value, // here
});
Use a value that comes from the state instead.
this.setState((prevState) => ({
select: !prevState.select,
}));
Note: You can remove the conditions from the render, they are redundant.

React a component is changing an uncontrolled input of type checkbox to be controlled

react gives me a warning: "A component is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa)."
However my checbox is change via the state property. Am I missing something obvious?
import React from 'react';
// Components
import Checkbox from './checkbox';
import HelpBubble from './helpBubble';
export default class CheckboxField extends React.Component {
constructor(props) {
super(props);
this.state = {value: props.value};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
componentWillReceiveProps(nextProps) {
if (nextProps.value !== this.props.value) {
this.setState({value: nextProps.value});
}
}
render() {
const {label, meta = {}, help, disabled, required, onChange} = this.props;
return (
<label className="checkbox-wrap form-field">
<Checkbox
disabled={disabled}
type="checkbox"
onChange={(event) => {
onChange(event, !this.state.value);
}}
checked={this.state.value}/>
{label && (
<div className="checkbox-label">
{label}
{required && <div className="form-field__required"/>}
</div>
)}
{help && <HelpBubble help={help}/>}
{meta.error && meta.touched && (
<div className="input-error">{meta.error}</div>
)}
</label>
);
}}
Parent component:
handleChangeParams(key, value)
}
/>
Handle change params changes the value in model and calls server. Depending on server result, the value can change.
Thanks in advance.
If your state is initialized with props.value being null React will consider your Checkbox component to be uncontrolled.
Try setting your initial state so that value is never null.
this.state = { value: props.value || "" };
If you are using a checkbox react won't like a string either so instead try
this.state = { checkboxValue: props.checkboxValue || false };
Something worth noting about the above code snippet. When you set a state in the constructor from props, it is always best to set the state to a "controlled" value i.e. a tangible value such as an int, float, string, array, map, etc. The error you are getting is the result of props.value being set to null
So, Consider setting your constructor state like this:
this.state = {
value: props.value ? props.value : 'empty'
}
What is happening here is it is checking if props.value has a value, if it does it sets the state to props.value, if props.value is null, it sets the state to the string: `'empty'
Another simple way to do this would be to !! your props.checkboxValue value. That way even if it's undefined, !!props.checkboxValue will resolve to false.
this.state = { checkboxValue: !!props.checkboxValue };
In my case, I was using a prop from my redux store to set whether the checkbox was checked, simply defaulting the property to false worked for me.
e.g.
const MyComponent = ({
somePropFromRedux
}) => {
return <thatThridPartyCheckboxComponent checked={somePropFromRedux} />
}
becomes (only change is adding = false on Line 2)
const MyComponent = ({
somePropFromRedux = false
}) => {
return <thatThridPartyCheckboxComponent checked={somePropFromRedux} />
}
do not use e.target.checked in the inputbox onChange eventHandler method.
Correct way:
const [isChecked, setCheck] = useState(false);
const handler = (e) => {
setCheck(!isChecked);
};
<input
type="checkbox"
checked={isChecked}
onChange={handler}
/>

Save textarea value to div with ReactJs

I'm only trying to deal with the React, so my question may seem very simple, but still I'm stuck on it.
I have two blocks (div.user-data__row) in which there are some values. I change the state of the component (handleChange function), the state in which these blocks are replaced by text fields (textarea.text), and I want when I click on the save button and call saveChange function, the value from each text field is taken and passed to the blocks (1st textarea to 1st block, etc).
I found examples of solving a similar case using the ref attribute, but later read that this is no longer an actual solution and so no one does. Please help me find the actual implementation path.
class UserData extends React.Component {
constructor(props) {
super(props);
this.state = {
edit: true,
};
this.handleChange = this.handleChange.bind(this);
this.saveChange = this.handleChange.bind(this);
}
handleChange() {
this.setState(() => ({
edit: !this.state.edit,
}));
}
saveChange() {
this.setState(() => ({
edit: false
}))
}
render() {
if (this.state.edit) {
return (
<div className="user-data">
<div className="user-data__row">{this.props.userData.name}</div>
<div className="user-data__row">{this.props.userData.email}</div>
<button onClick={ this.handleChange }>Edit</button>
</div>
);
} else {
return (
<div className="user-data">
<textarea className="text" defaultValue={this.props.userData.name}></textarea>
<textarea className="text" defaultValue={this.props.userData.email}></textarea>
<button onClick={ this.saveChange }>Save</button>
</div>
)
}
}
}
Because props are read-only & because userData (email+name) can be changed inside the component , you have to populate props values in the state, then manage the state after that will be enough.
Also , you will need to convert your textarea from uncontrolled component to controlled component by:
Using value instead of defaultValue
Implementing onChange with setState of that value as handler .
Value of textarea should be read from state not props.
If props of <UserData /> may be updated from outside throughout its lifecycle , you will need componentWillReceiveProps later on.
Also you have a typo if (!this.state.edit) { and not if (this.state.edit) { .
class UserData extends React.Component {
state = {
edit: true,
userDataName: this.props.userData.name, // Populate props values
userDataEmail: this.props.userData.email, // Populate props values
};
handleChange = () => {
this.setState((state) => ({
edit: !state.edit,
}));
}
saveChange =() => {
this.setState(() => ({
edit: false
}))
}
render() {
if (!this.state.edit) {
return (
<div className="user-data">
<div className="user-data__row">{this.state.userDataName}</div>
<div className="user-data__row">{this.state.userDataEmail}</div>
<button onClick={ this.handleChange }>Edit</button>
</div>
);
} else {
return (
<div className="user-data">
<textarea className="text" value={this.state.userDataName} onChange={(e) => this.setState({userDataName: e.target.value})}></textarea>
<textarea className="text" value={this.state.userDataEmail} onChange={(e) => this.setState({userDataEmail: e.target.value})}></textarea>
<button onClick={ this.saveChange }>Save</button>
</div>
)
}
}
}
ReactDOM.render(<UserData userData={{name: 'Abdennoor', email: 'abc#mail.com'}} /> , document.querySelector('.app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div class="app" />
You're receiving values for <div> from this.props, it means that these values should came from some external source and passed to your component. A way of passing these values to component's props is out of scope of this question, it can be implemented in a very different ways. Usually it came either from parent component or from some connected store.
You need to obtain values from your <textarea> form fields, it can be done directly (using ref) or by using some third-party library that provides form handling. Then these values needs to be stored (and obtained) either directly from component's state or from external source (via props).
Unfortunately scope of your question is too broad to be able to give more precise answer, but hope that this information will lead you to some kind of solution.
You can also use contentEditable, which it will allow you to edit the content of the div.
class UserData extends React.Component {
constructor(props) {
super(props);
this.state = {
edit: true
};
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.setState(() => ({
edit: !this.state.edit
}));
}
render() {
const { edit } = this.state;
return (
<div className="user-data">
<div className="user-data__row" contentEditable={edit}>{this.props.userData.name}</div>
<div className="user-data__row" contentEditable={edit}>{this.props.userData.email}</div>
<button onClick={this.handleChange}>
{edit ? Save : Edit}
</button>
</div>
)
}
}

React - changing an uncontrolled input

I have a simple react component with the form which I believe to have one controlled input:
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange('name').bind(this)}/>
</form>
)
}
onFieldChange(fieldName) {
return function (event) {
this.setState({[fieldName]: event.target.value});
}
}
}
export default MyForm;
When I run my application I get the following warning:
Warning: MyForm is changing an uncontrolled input of type text to be
controlled. Input elements should not switch from uncontrolled to
controlled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component
I believe my input is controlled since it has a value. I am wondering what am I doing wrong?
I am using React 15.1.0
I believe my input is controlled since it has a value.
For an input to be controlled, its value must correspond to that of a state variable.
That condition is not initially met in your example because this.state.name is not initially set. Therefore, the input is initially uncontrolled. Once the onChange handler is triggered for the first time, this.state.name gets set. At that point, the above condition is satisfied and the input is considered to be controlled. This transition from uncontrolled to controlled produces the error seen above.
By initializing this.state.name in the constructor:
e.g.
this.state = { name: '' };
the input will be controlled from the start, fixing the issue. See React Controlled Components for more examples.
Unrelated to this error, you should only have one default export. Your code above has two.
When you first render your component, this.state.name isn't set, so it evaluates to undefined or null, and you end up passing value={undefined} or value={null}to your input.
When ReactDOM checks to see if a field is controlled, it checks to see if value != null (note that it's !=, not !==), and since undefined == null in JavaScript, it decides that it's uncontrolled.
So, when onFieldChange() is called, this.state.name is set to a string value, your input goes from being uncontrolled to being controlled.
If you do this.state = {name: ''} in your constructor, because '' != null, your input will have a value the whole time, and that message will go away.
Another approach it could be setting the default value inside your input, like this:
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
I know others have answered this already. But a very important factor here that may help other people experiencing similar issue:
You must have an onChange handler added in your input field (e.g. textField, checkbox, radio, etc). Always handle activity through the onChange handler.
Example:
<input ... onChange={ this.myChangeHandler} ... />
When you are working with checkbox you may need to handle its checked state with !!.
Example:
<input type="checkbox" checked={!!this.state.someValue} onChange={.....} >
Reference: https://github.com/facebook/react/issues/6779#issuecomment-326314716
Simple solution to resolve this problem is to set an empty value by default :
<input name='myInput' value={this.state.myInput || ''} onChange={this.handleChange} />
One potential downside with setting the field value to "" (empty string) in the constructor is if the field is an optional field and is left unedited. Unless you do some massaging before posting your form, the field will be persisted to your data storage as an empty string instead of NULL.
This alternative will avoid empty strings:
constructor(props) {
super(props);
this.state = {
name: null
}
}
...
<input name="name" type="text" value={this.state.name || ''}/>
I had the same problem.
the problem was when i kept the state info blank
const [name, setName] = useState()
I fixed it by adding empty string like this
const [name, setName] = useState('')
In my case, I was missing something really trivial.
<input value={state.myObject.inputValue} />
My state was the following when I was getting the warning:
state = {
myObject: undefined
}
By alternating my state to reference the input of my value, my issue was solved:
state = {
myObject: {
inputValue: ''
}
}
When you use onChange={this.onFieldChange('name').bind(this)} in your input you must declare your state empty string as a value of property field.
incorrect way:
this.state ={
fields: {},
errors: {},
disabled : false
}
correct way:
this.state ={
fields: {
name:'',
email: '',
message: ''
},
errors: {},
disabled : false
}
If the props on your component was passed as a state, put a default value for your input tags
<input type="text" placeholder={object.property} value={object.property ? object.property : ""}>
Set a value to 'name' property in initial state.
this.state={ name:''};
An update for this. For React Hooks use const [name, setName] = useState(" ")
Simply create a fallback to '' if the this.state.name is null.
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
This also works with the useState variables.
I believe my input is controlled since it has a value.
Now you can do this two ways the best way is to have a state key to each input with 1 onChange handler. If you have checkboxes you will need to write a separate onChange handler.
With a Class component you would want to write it like this πŸ‘‡
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
myFormFields: {
name: '',
dob: '',
phone: ''
}
}
this.onFormFieldChange = this.onFormFieldChange.bind(this)
}
// Always have your functions before your render to keep state batches in sync.
onFormFieldChange(e) {
// No need to return this function can be void
this.setState({
myFormFields: {
...this.state.myFormFields,
[e.target.name]: e.target.value
}
})
}
render() {
// Beauty of classes we can destruct our state making it easier to place
const { myFormFields } = this.state
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={this.onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={this.onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={this.onFormFieldChange}/>
</form>
)
}
}
export default MyForm;
Hope that helps for a class but the most performative and what the newest thing the devs are pushing everyone to use is Functional Components. This is what you would want to steer to as class components don't intertwine well with the latest libraries as they all use custom hooks now.
To write as a Functional Component
import React, { useState } from 'react';
const MyForm = (props) => {
// Create form initial state
const [myFormFields, setFormFields] = useState({
name: '',
dob: '',
phone: ''
})
// Always have your functions before your return to keep state batches in sync.
const onFormFieldChange = (e) => {
// No need to return this function can be void
setFormFields({
...myFormFields,
[e.target.name]: e.target.value
})
}
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={onFormFieldChange}/>
</form>
)
}
export default MyForm;
Hope this helps! 😎
In short, if you are using class component you have to initialize the input using state, like this:
this.state = { the_name_attribute_of_the_input: "initial_value_or_empty_value" };
and you have to do this for all of your inputs you'd like to change their values in code.
In the case of using functional components, you will be using hooks to manage the input value, and you have to put initial value for each input you'd like to manipulate later like this:
const [name, setName] = React.useState({name: 'initialValue'});
If you'd like to have no initial value, you can put an empty string.
In my case component was rerendering and throwing A component is changing an uncontrolled input of type checkbox to be controlled error. It turned out that this behaviour was a result of not keeping true or false for checkbox checked state (sometimes I got undefined). Here what my faulty component looked like:
import * as React from 'react';
import { WrappedFieldProps } from 'redux-form/lib/Field';
type Option = {
value: string;
label: string;
};
type CheckboxGroupProps = {
name: string;
options: Option[];
} & WrappedFieldProps;
const CheckboxGroup: React.FC<CheckboxGroupProps> = (props) => {
const {
name,
input,
options,
} = props;
const [value, setValue] = React.useState<string>();
const [checked, setChecked] = React.useState<{ [name: string]: boolean }>(
() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}),
);
React.useEffect(() => {
input.onChange(value);
if (value) {
setChecked({
[value]: true, // that setChecked argument is wrong, causes error
});
} else {
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}));
}
}, [value]);
return (
<>
{options.map(({ value, label }, index) => {
return (
<LabeledContainer
key={`${value}${index}`}
>
<Checkbox
name={`${name}[${index}]`}
checked={checked[value]}
value={value}
onChange={(event) => {
if (event.target.checked) {
setValue(value);
} else {
setValue(undefined);
}
return true;
}}
/>
{label}
</LabeledContainer>
);
})}
</>
);
};
To fix that problem I changed useEffect to this
React.useEffect(() => {
input.onChange(value);
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = option.value === value;
return accu;
}, {}));
}, [value]);
That made all checkboxes keep their state as true or false without falling into undefined which switches control from React to developer and vice versa.
For people using Formik, you need to add a default value for the specific field name to the form's initialValues.
This generally happens only when you are not controlling the value of the filed when the application started and after some event or some function fired or the state changed, you are now trying to control the value in input field.
This transition of not having control over the input and then having control over it is what causes the issue to happen in the first place.
The best way to avoid this is by declaring some value for the input in the constructor of the component.
So that the input element has value from the start of the application.
Please try this code
import React from "react";
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = { name: "" };
this.onFieldChange = this.onFieldChange.bind(this);
}
onFieldChange(e) {
this.setState({[e.target.name]: e.target.value});
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange} />
</form>
);
}
}
export default MyForm;
In my case there was spell mistake while setting the state which was causing defined value to be undefined.
This is my default state with value
const [email, setEmail] = useState(true);
my mistake was-
setEmail(res?.data?.notificationSetting.is_email_notificatio);
and the solution is -
setEmail(res?.data?.notificationSetting.is_email_notification);
last char was missing
I had the same issue with type='radio'
<input type='radio' checked={item.radio} ... />
the reason was that item.radio is not always true or false, but rather true or undefined, for example. Make sure it’s always boolean, and the problem will go away.
<input type='radio' checked={!!item.radio} ... />
source
For dynamically setting state properties for form inputs and keeping them controlled you could do something like this:
const inputs = [
{ name: 'email', type: 'email', placeholder: "Enter your email"},
{ name: 'password', type: 'password', placeholder: "Enter your password"},
{ name: 'passwordConfirm', type: 'password', placeholder: "Confirm your password"},
]
class Form extends Component {
constructor(props){
super(props)
this.state = {} // Notice no explicit state is set in the constructor
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({
[name]: value
}
}
handleSubmit = (e) => {
// do something
}
render() {
<form onSubmit={(e) => handleSubmit(e)}>
{ inputs.length ?
inputs.map(input => {
const { name, placeholder, type } = input;
const value = this.state[name] || ''; // Does it exist? If so use it, if not use an empty string
return <input key={name} type={type} name={name} placeholder={placeholder} value={value} onChange={this.handleChange}/>
}) :
null
}
<button type="submit" onClick={(e) => e.preventDefault }>Submit</button>
</form>
}
}

Categories