2

I'm using ReactJS and I need to change the status of the values ​​but the value property is in the state in this way:

this.state = {
         form:{
                name:{
                    value:''
                 }
              }  
         }     

I tried it in different ways on the form like:

<TextInput
 name='form.name.value'
 value={this.state.form.name.value}
 onChange={value => this.onChange('name', value)}
/>


 onChange = (e) => { 
    this.setState({ [e.target.name]: e.target.value})
}  

But never changes the value on state.

How can I do this? thanks!!!!!!

2
  • you used TextInput is it react-native or reactjs ? If reactjs and custom input field then show code of TextInput. Else reactjs input means HTML does not provide value directly in onChange Commented Aug 17, 2018 at 6:50
  • Text Input is just an input on ReactJS: <div className="input-field"> <i className="material-icons prefix">{icon}</i> <input name={name} value={value} onChange={onChange} label={label} type={type} /> </div> Commented Aug 17, 2018 at 6:53

5 Answers 5

1

The way you have used the input field name is incorrect.In the setState it is considered as string rather than a object.key.

onChange= (e) => {
    let inputName = e.target.name;
     let inputValue = e.target.value;
     let updatedFormState = Object.assign({}, this.state);
     updatedFormState.form[inputName].value = inputValue;
     this.setState(updatedFormState);
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks bro but dont work: TypeError: Cannot read property 'name' of null
@OscarDev its because of SyntheticEvent concept, check this answer
Thank you friend this works perfectly! I will review more about Object.assign that I have not used it for some time. Thank you!
I'm refactoring and it works great, thank you very much: let inputName = e.target.name; let inputValue = e.target.value; let form = {...this.state.form} form[inputName].value = inputValue; this.setState(form)
1

Your onChange function should be changed to

onChange = (e) => { 
    this.setState({ form: {...this.state.form, [e.target.name]: e.target.value}})
}

Edit: I was able to run the below code successfully

class App extends React.Component {
  state = {
    form: {
       test: ""
    }
  }
  onChange = (e) => {
    this.setState({
      form: {
        ...this.state.form,
        [e.nativeEvent.target.name]: e.target.value,
      }
    })
  }
  render() {
    return <div>
      <TextInput 
       name='test'
       value={this.state.form.test}
       onChange={this.onChange}
      />
      <br/><br/>
      The State : {JSON.stringify(this.state)}
    </div>;
  }
}

const TextInput = (props) => {
  return <input type="text" {...props}/>;
}

ReactDOM.render(
  <App />,
  document.getElementById('container')
);
<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 id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

Edit: As per your new structure I have made the changes

class App extends React.Component {
  state = {
    form: {
       test: {
         value: "",
         type: "text"
       }
    }
  }
  onChange = (e) => {
    this.setState({
      form: {
        ...this.state.form,
        [e.nativeEvent.target.name]: {
            ...this.state.form[e.nativeEvent.target.name],
            value: e.nativeEvent.target.value
        },
      }
    })
  }
  render() {
    return <div>
      <CustomInput 
       name='test'
       value={this.state.form.test.value}
       onChange={this.onChange}
      />
      <br/><br/>
      The State : {JSON.stringify(this.state)}
    </div>;
  }
}

const CustomInput = (props) => {
  return <input {...props}/>;
}

ReactDOM.render(
  <App />,
  document.getElementById('container')
);
<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 id="container"></div>

3 Comments

I tried with your example but the state change like this: State form:{...} name: 'test' And lost the object.
It works as long as the status is something like: State = { form: { name: " " } } But if the state is something like: State = { form: { name: { value=" ", type: " "} } } Your solution overwrites the "name" object and leaves it without its properties: State = { form: { name:" " } }
@OscarDev I have added my modified code snippet to accommodate your requirement
0

In order to setState for a nested object you can follow the below approach as I think setState doesn't handle nested updates.

let form = {...this.state.form}
let name = [e.target.name];
form.name = e.target.value;
this.setState({form});

The idea is to create a dummy object perform operations on it and then replace the component's state with the updated object

1 Comment

I tried but I can change only the state of name if I add a new property like form.surname.value I cant use the input text.
0

I dont know your scenario but I think you are doing wrong practice. Solution to you problem:

<TextInput
          name="form.name.value"
          value={this.state.form.name.value}
          onChange={(a, b) => this.handleTextChange(a, b)}
        />

Now handleTextChange like

 handleTextChange(name, value) {
    const arr = name.split(".");
    const obj = {
      [arr[2]]: value
    };
    const nameObj = {
      [arr[1]]: { ...obj }
    };

    console.log("fomr", nameObj);
    this.setState({ form: nameObj });
  }

Considering you customComponent

const TextInput = props => {
  return (
    <input
      name={props.name}
      onChange={e => props.onChange(e.target.name, e.target.value)}
    />
  );
};

CodeSandbox working example

1 Comment

form.name.value string as name where doing wrong but may b this is because of scenario
0

You need to use destructuring wiht es6:

I have created a working copy here: CodePen InputForm

var sp = {...this.state.form};
sp.name.value = event.target.value;

this.setState({sp})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.